如何控制Linux线程数? (linux运行线程数如何控制器)

随着互联网的不断发展和技术的进步,操作系统的公司不断推陈出新,而Linux作为一款自由开源、功能强大的操作系统,备受开发者和用户的欢迎。Linux中一个线程可以使用一个CPU的所有时间片,CPU计算机的数量越多,线程数就能达到更高的阈值,尤其是对于多核CPU来说,我们可以更加有效地使用多核CPU的优势。

然而,随着线程数的增加,系统资源的负载也会随之增加。因此,了解如何控制Linux线程数将有助于我们更好地进行系统管理和优化。

本文将介绍一些我们可以使用的策略来控制Linux线程数。

1.使用ulimit命令

Linux中的ulimit命令可以帮助我们限制一个进程在用户级别的资源使用(包括文件打开数量、核心文件大小、进程数量等),这也可以用来限制线程数量。您可以使用以下命令来限制线程数量:

$ ulimit -u

在这里,-u选项表示限制线程数。像下面这样执行该命令:

$ ulimit -u 500

这将限制用户为500个线程。请注意,该限制将适用于当前Shell会话中运行的所有新进程和线程。

2.使用cgroups控制组

Linux提供的另一种资源限制机制是cgroups。cgroups(control groups)是一种在Linux内核中实现的,用于限制、隔离和控制进程组的蘑菇。您可以使用cgroups来限制线程的数量和使用资源,包括CPU和内存的使用情况。

要使用cgroups限制线程数,请按照以下步骤操作:

(a) 首先创建一个新的控制组,在以下路径中创建:

$ sudo mkdir /sys/fs/cgroup/thread-limit

(b) 接下来,使用cgroup.controllers文件将控制器分配给线程限制:

$ echo +pids > /sys/fs/cgroup/thread-limit.cgroup.subtree_control

(c) 设置限制线程数的值限制,使用以下命令:

$ echo 1000 > /sys/fs/cgroup/thread-limit/pids.max

在这个例子中,我们限制线程数为1000。

(d) 使用以下命令为一个新进程启用控制组:

$ sudo cgexec -g “pids:/thread-limit”

以上命令将在新进程中启用pids控制器,并将控制组分配给/thread-limit。

3.使用/proc/sys/kernel/threads-max文件

Linux还提供了一个/sys/kernel/threads-max文件,可以用来设置系统级别的线程限制。这个文件包含一个数字,表示可以创建的阈值线程总数。

要更改线程更大值,请执行以下操作:

(a) 使用文本编辑器打开/proc/sys/kernel/threads-max文件:

$ sudo vi /proc/sys/kernel/threads-max

(b) 将文件中的数字更改为所需的更大线程数。

(c) 保存并关闭文件。

请注意,更改此值需要root权限。

相关问题拓展阅读:

Linux中,shell脚本如何使用信号机制去控制线程的开启关闭

trap是Linux的内建命令,用于捕捉信号,trap命令可以指定收到某种信号时所执行的命令。trap命令的格式如下:trap command sig1 sig2 … sigN,当接收到sinN中任意一个信号时,执行command命令,command命令完成后继续接收到信号前的操作,直到脚本结束。 利用trap命令捕捉INT信号(即与Ctrl+c绑定的中断信号)。trap还可以忽略某些信号,将command用空字符串代替即可,如trap “” TERM INT,忽略kill %n和Ctrl+c发送的信号(kill发送的是TERM信号)。Linux更强劲的杀死进程的命令:kill -9 进程号(或kill -9 %n作业号)等价与kill -KILL 进程号。

举个例子

  最近小A需要生产2023年全年的KPI数据报表,现在小A已经将生产脚本猛举租写好了,生产脚本一次只能生产指定一天的KPI数据,假设跑一次生产脚本需要5分钟,那么:

  如果是循环顺序执行,那么需要时间:5 * 365 = 1825 分钟,约等于 6 天

  如果是一次性放到linux后台并发执行,365个后台任务,系统可承受不住哦!

  既然不能一次性把365个任务放到linux后台执行,那么,能不能实现自动地每次将N个任务放到后台并发执行呢?当然是可以的啦。

   #! /bin/bash

source /etc/profile;

#–

tempfifo=$$.fifo# $$表示当前执行文件的PID

begin_date=$# 开始时间

end_date=$# 结束时间

if  

then

   if  “$end_date” >

   then

echo “Error! $begin_date is greater than $end_date”

exit 1;

   fi

else

   echo “Error! Not enough params.”

   echo “Sample: sh loop_kpi”

   exit 2;

fi

#–

trap “exec 1000>&-;exec 1000$tempfifo

rm -rf $tempfifo

for ((i=1; i&1000

done

while 

do

   read -u1000

   {

echo $begin_date

hive -f kpi_report.sql –hivevar date=$begin_date

echo >&1000

   } &

   begin_date=`date -d “+1 day $begin_date” +”%Y-%m-%d”`

done

wait

echo “done!!!!!!!!!!”

   

第6~22行:比如:sh loop_kpi_report.sh:

$1表示脚本入参的之一个参数,等于

$2表示脚本入参的第二个参数,等于

$#表示脚本入参的个数,等于2

第13行用于比较传入的两个日期的大小,\>是转义

第26行:表示在脚本运行过程中,如果接收到Ctrl+C中断命令,则关闭文件描述符1000的读写,并正常退出

exec 1000>&-;表示关闭文件描述符1000的写

exec 1000写的绑定,则标识对文件描述符1000的所有操作等同于对管道文件$tempfifo的操作

第29行,可能会有这样的枝兆疑问:为什么不直接使用管道文件呢?事实上这并非多此一举,管道的一个重要特性,就是读写必须同时存在,缺失某一个操作,另一个操作就是滞留,而第28行的绑定文件描述符(读、写绑定)正好解决了这个问题

第31~34行:对文件描述符1000进行写入操作。通过循环写入8个空行,这个8就是我们要定义的后台并发的线程数。为什么是写空行而不是写其它字符?因为管道文件的读取,是以行为单位的

第37~42行:

第37行,read -u1000的作用就是读取管道中的一行,在这里就是读取一个空行;每次读取管道就会减少一个空行

第39~41行,注意到第42行结尾的&吗?它表示进程放到linux后台中执行

第41行,执行完后台任务之后,往文件描述符1000中写入一个空行。这是关键所在了,由于read -u1000每次操作,都会导致管道减少一个空行,当linux后台放入了8个任务之后,由于文件描述符1000没有可读取的空行,将导致read -u1000一直处于等待。

linux下线程属性常用操作有哪些

LinuxThread的线程机制

LinuxThreads是目前Linux平台上使用最为广泛的线程库,由Xavier Leroy () 负责开发完成,并已绑定在GLIBC中发行。它所实现的就是基于核心轻量级进程的”一对一”线程模型,一个线程实体对应一个核心轻量级进程,而线程之间的 管理在核外函数库中实现。

1.线程描述数据结构及实现限制

LinuxThreads定义了一个struct _pthread_descr_struct数据结构来描述线程,并使用全局数组变量 __pthread_handles来描晌胡基述和引用进程所辖线程。在__pthread_handles中的前两项,LinuxThreads定义了两个全 局的系统线程:__pthread_initial_thread和__pthread_manager_thread,并用 __pthread_main_thread表征__pthread_manager_thread的父线程(初始为 __pthread_initial_thread)。

struct _pthread_descr_struct是一个双环链表结构,__pthread_manager_thread所在的链表仅包括它 一个元素,实际上,__pthread_manager_thread是一个特殊线程,LinuxThreads仅使用了其中的errno、p_pid、 p_priority等三个域。而__pthread_main_thread所在的链则将进程中所有用户线程串在了一起。经过一系列 pthread_create()之后形成的__pthread_handles数组将如下图所示:

图2 __pthread_handles数组结构

新创建的线程将首先在__pthread_handles数组中占据一项,然后通过数据结构中的链指针连入以__pthread_main_thread为首指针的链表中。这个链表的使用在介绍线程的创建和释放的时候将提到。

LinuxThreads遵循POSIX1003.1c标准,其中对线程库的实现进行了一些范围限制,比如进程更大线程数,线程私有数据区大小等等。在 LinuxThreads的实现中,基本遵循这些限制,但也进行了一定的改动,改动的趋势是放松或者说扩大这些限制,使编程更加方便。这些限定宏主要集中 在sysdeps/unix/sysv/linux/bits/local_lim.h(不同平台使用的文件位置不同)中,包括如下几个:

每进程的私有数据key数,POSIX定义_POSIX_THREAD_KEYS_MAX为128,LinuxThreads使用 PTHREAD_KEYS_MAX,1024;私有数据释放时允许执行的操作数,LinuxThreads与POSIX一致,定义 PTHREAD_DESTRUCTOR_ITERATIONS为4;每进程的线程数,POSIX定义为64,LinuxThreads增大到1024 (PTHREAD_THREADS_MAX);线程运行栈最小空间大小,POSIX未指定,LinuxThreads使用 PTHREAD_STACK_MIN,16384(字节)。

2.管理线程

“一对一”模型的好处之一是线程的调度由核心完成了,而其他诸如线程取消、线程间的同步等工作,宴谨都是在核外线程库中完成的。在LinuxThreads 中,专门为每一个进程构造了一个管理线程,负责处理线程相关的管理工作。当进程之一次调用pthread_create()创建一个线程的时候就会创建 (__clone())并启动管理线程。

在一个进程空间内,管理线程与其他线程之间通过一对”管理管道(manager_pipe)”来通讯,该管道在创建管理线程之前创建,在成功启动 了管理线程之后,管理管道的读端和写端分别做姿赋给两个全局变量__pthread_manager_reader和 __pthread_manager_request,之后,每个用户线程都通过__pthread_manager_request向管理线程发请求, 但管理线程本身并没有直接使用__pthread_manager_reader,管道的读端(manager_pipe)是作为__clone ()的参数之一传给管理线程的,管理线程的工作主要就是监听管道读端,并对从中取出的请求作出反应。

创建管理线程的流程如下所示:

(全局变量pthread_manager_request初值为-1)

图3 创建管理线程的流程

初始化结束后,在__pthread_manager_thread中记录了轻量级进程号以及核外分配和管理的线程id, 2*PTHREAD_THREADS_MAX+1这个数值不会与任何常规用户线程id冲突。管理线程作为pthread_create()的调用者线程的 子线程运行,而pthread_create()所创建的那个用户线程则是由管理线程来调用clone()创建,因此实际上是管理线程的子线程。(此处子 线程的概念应该当作子进程来理解。)

__pthread_manager()就是管理线程的主循环所在,在进行一系列初始化工作后,进入while(1)循环。在循环中,线程以2秒为 timeout查询(__poll())管理管道的读端。在处理请求前,检查其父线程(也就是创建manager的主线程)是否已退出,如果已退出就退出 整个进程。如果有退出的子线程需要清理,则调用pthread_reap_children()清理。

然后才是读取管道中的请求,根据请求类型执行相应操作(switch-case)。具体的请求处理,源码中比较清楚,这里就不赘述了。

3.线程栈

在LinuxThreads中,管理线程的栈和用户线程的栈是分离的,管理线程在进程堆中通过malloc()分配一个THREAD_MANAGER_STACK_SIZE字节的区域作为自己的运行栈。

用户线程的栈分配办法随着体系结构的不同而不同,主要根据两个宏定义来区分,一个是NEED_SEPARATE_REGISTER_STACK,这个属 性仅在IA64平台上使用;另一个是FLOATING_STACK宏,在i386等少数平台上使用,此时用户线程栈由系统决定具置并提供保护。与此同 时,用户还可以通过线程属性结构来指定使用用户自定义的栈。因篇幅所限,这里只能分析i386平台所使用的两种栈组织方式:FLOATING_STACK 方式和用户自定义方式。

在FLOATING_STACK方式下,LinuxThreads利用mmap()从内核空间中分配8MB空间(i386系统缺省的更大栈空间大小,如 果有运行限制(rlimit),则按照运行限制设置),使用mprotect()设置其中之一页为非访问区。该8M空间的功能分配如下图:

图4 栈结构示意

低地址被保护的页面用来监测栈溢出。

对于用户指定的栈,在按照指针对界后,设置线程栈顶,并计算出栈底,不做保护,正确性由用户自己保证。

不论哪种组织方式,线程描述结构总是位于栈顶紧邻堆栈的位置。

4.线程id和进程id

linux运行线程数如何控制器的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux运行线程数如何控制器,如何控制Linux线程数?,Linux中,shell脚本如何使用信号机制去控制线程的开启关闭,linux下线程属性常用操作有哪些的信息别忘了在本站进行查找喔。


数据运维技术 » 如何控制Linux线程数? (linux运行线程数如何控制器)