Linux中每个过程的最大线程数
1. 概述
众所周知,进程是当前正在运行的程序,而线程 是半进程或轻量级进程。
在本教程中,我们将讨论什么是多线程进程。此外,我们将了解为什么 Linux 中每个进程的线程数有限制,以及这个限制是什么。
2. 什么是多线程进程?
在共享内存空间中为同一程序提供多个执行线程称为多线程。
多线程进程使我们能够同时运行多个线程。多线程的目的是提高性能。
为了获得最佳性能,Linux 对线程数有限制。可以设置threads-max内核参数以确保每个进程的线程数始终小于或等于该限制。但是,其他因素(如虚拟内存量和堆栈大小)可能会间接控制分配给进程的线程数。
3. 每个进程的线程数限制
Linux 有一个每个进程的最大线程数设置,它指定进程可以处理的最大同时执行数。
对此的更改可以限制进程并最大限度地减少发生执行的延迟。
**达到此限制意味着该进程在峰值负载时需要那么多线程。**但是,只要它能够及时处理请求,就可以充分调整该过程。
但是,当达到限制时,线程会排队,可能会使进程超载。此时,进程推迟创建新线程,直到活动线程的数量低于限制。
4.如何检索最大线程数
内核参数 threads-max控制最大线程数。
此参数在文件*/proc/sys/kernel/threads-max*中定义。
让我们使用cat 命令查看这个文件:
$ cat /proc/sys/kernel/threads-max
63704
这里,输出 63704 表示内核最多可以执行 63,704 个线程。
或者,我们可以使用*sysctl 命令来检索线程最大值*:
$ sysctl -a | grep threads-max
kernel.threads-max = 63704
** kernel.pid_max和vm.max_map_count指定了另外两个限制,它们也会在峰值负载时阻止新线程的创建。**
pid_max参数指定 PID 环绕的值:
$ cat /proc/sys/kernel/pid_max
131072
上面的kernel.pid_max值为 131072 意味着内核最多可以同时执行 131,072 个进程。
max_map_count参数指定进程可以拥有的虚拟内存区 (VMA) 的最大数量:
$ cat /proc/sys/vm/max_map_count
65530
上面的vm.max_map_count值 65530 是一个进程可能拥有的内存映射区域的最大数量。
Linux 内核以相同的方式处理进程和线程。因此,限制进程数的值也会间接限制线程数。
因此,kernel.pid_max必须大于并发线程和进程的总数。
拥有许多线程可能会消耗太多内存以使服务器无法工作。vm.max_map_count限制虚拟内存和需要此内存来设置自己的私有堆栈的线程数。
在systemd系统上,cgroup pids.max参数强制执行另一个限制。默认设置为 12,288。在某些情况下,此默认资源限制是不够的,或者可能过于严格。
或者,对systemd 的某些 TasksMax设置进行特定调整可能会很有用。/etc/systemd/logind.conf 的*[Login]部分中的UserTasksMax*参数会覆盖默认限制:
$ grep -i "^UserTasksMax" /etc/systemd/logind.conf
UserTasksMax=50000
这正是systemd对从登录 shell 运行的程序应用线程限制的方式。
5. 如何设置最大线程数
有几种方法可以设置每个进程的最大线程数。这些值决定了一个进程将被允许多少个线程。
让我们在运行时临时设置threads-max内核参数:
$ echo 120000 > /proc/sys/kernel/threads-max
我们可以通过将kernel.threads-max=value添加到/etc/sysctl.conf文件来永久设置kernel.threads-max*参数:*
$ sysctl -w kernel.threads-max=120000 >> /etc/sysctl.conf
接下来,将pid_max参数设置为 200000 意味着内核最多可以同时执行 200,000 个进程:
$ echo 200000 > /proc/sys/kernel/pid_max
类似地,将max_map_count参数设置为 600000 意味着一个进程最多可以拥有 600,000 个虚拟内存区域 (VMA):
$ echo 600000 > /proc/sys/vm/max_map_count
在systemd系统上, UserTasksMax为所有用户 指定TasksMax设置并确定线程限制:
$ sed -i "s/^UserTasksMax/#UserTasksMax/" /etc/systemd/system.conf
$ echo "UserTasksMax=60000" >> /etc/systemd/system.conf
$ grep -i "UserTasksMax" /etc/systemd/logind.conf
#UserTasksMax=50000
UserTasksMax=60000
6. 影响最大线程数的因素
尽管有一些系统参数限制了每个进程的线程数,但操作系统和内存很可能在此之前成为限制因素。
进程可以拥有的线程数限制使用以下公式计算:
** 线程数=总虚拟内存/(堆栈大小*1024*1024) **
因此,可以通过增加总虚拟内存 来增加每个进程的线程数。每个线程的堆栈大小比其他任何东西都更有可能成为限制。减少每个线程的堆栈大小也是增加线程总数的一种方法。
我们可以使用ulimit 检查每个线程的堆栈大小:
$ ulimit -a | grep "stack size"
stack size (kbytes, -s) 10240
该值表示每个线程都将获得为其堆栈分配的内存量 (10MB)。对于 32 位程序和 4GB 的最大地址空间,最大线程数将是:
4096MB / 10MB = 409
在 64 位处理器上,我们可以使用ulimit调整每个线程的堆栈大小:
$ ulimit -s 8192