Contents

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_maxvm.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