随着互联网的不断发展和技术的进步,操作系统的公司不断推陈出新,而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权限。
:
成都网站建设公司-创新互联,建站经验丰富以策略为先导10多年以来专注数字化网站建设,提供企业网站建设,高端网站设计,响应式网站制作,设计师量身打造品牌风格,热线:028-86922220trap是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一直处于等待。
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下线程属性常用操作有哪些的信息别忘了在本站进行查找喔。
创新互联【028-86922220】值得信赖的成都网站建设公司。多年持续为众多企业提供成都网站建设,成都品牌建站设计,成都高端网站制作开发,SEO优化排名推广服务,全网营销让企业网站产生价值。
网页名称:如何控制Linux线程数?(linux运行线程数如何控制器)
URL链接:http://www.shufengxianlan.com/qtweb/news36/148586.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联