python的多进程
❶ python中的多进程与多线程/分布式该如何使用
Python提供了非常好用的多进程包multiprocessing,你只需要定义一个函数,Python会替你完成其他所有事情。
借助这个包,可以轻松完成从单进程到并发执行的转换。
1、新建单一进程
如果我们新建少量进程,可以如下:
import multiprocessing
import time
def func(msg):
for i in xrange(3):
print msg
time.sleep(1)
if __name__ == "__main__":
p = multiprocessing.Process(target=func, args=("hello", ))
p.start()
p.join()
print "Sub-process done."12345678910111213
2、使用进程池
是的,你没有看错,不是线程池。它可以让你跑满多核CPU,而且使用方法非常简单。
注意要用apply_async,如果落下async,就变成阻塞版本了。
processes=4是最多并发进程数量。
import multiprocessing
import time
def func(msg):
for i in xrange(3):
print msg
time.sleep(1)
if __name__ == "__main__":
pool = multiprocessing.Pool(processes=4)
for i in xrange(10):
msg = "hello %d" %(i)
pool.apply_async(func, (msg, ))
pool.close()
pool.join()
print "Sub-process(es) done."12345678910111213141516
3、使用Pool,并需要关注结果
更多的时候,我们不仅需要多进程执行,还需要关注每个进程的执行结果,如下:
import multiprocessing
import time
def func(msg):
for i in xrange(3):
print msg
time.sleep(1)
return "done " + msg
if __name__ == "__main__":
pool = multiprocessing.Pool(processes=4)
result = []
for i in xrange(10):
msg = "hello %d" %(i)
result.append(pool.apply_async(func, (msg, )))
pool.close()
pool.join()
for res in result:
print res.get()
print "Sub-process(es) done."
2014.12.25更新
根据网友评论中的反馈,在Windows下运行有可能崩溃(开启了一大堆新窗口、进程),可以通过如下调用来解决:
multiprocessing.freeze_support()1
附录(自己的脚本):
#!/usr/bin/python
import threading
import subprocess
import datetime
import multiprocessing
def dd_test(round, th):
test_file_arg = 'of=/zbkc/test_mds_crash/1m_%s_%s_{}' %(round, th)
command = "seq 100 | xargs -i dd if=/dev/zero %s bs=1M count=1" %test_file_arg
print command
subprocess.call(command,shell=True,stdout=open('/dev/null','w'),stderr=subprocess.STDOUT)
def mds_stat(round):
p = subprocess.Popen("zbkc mds stat", shell = True, stdout = subprocess.PIPE)
out = p.stdout.readlines()
if out[0].find('active') != -1:
command = "echo '0205pm %s round mds status OK, %s' >> /round_record" %(round, datetime.datetime.now())
command_2 = "time (ls /zbkc/test_mds_crash/) 2>>/round_record"
command_3 = "ls /zbkc/test_mds_crash | wc -l >> /round_record"
subprocess.call(command,shell=True)
subprocess.call(command_2,shell=True)
subprocess.call(command_3,shell=True)
return 1
else:
command = "echo '0205 %s round mds status abnormal, %s, %s' >> /round_record" %(round, out[0], datetime.datetime.now())
subprocess.call(command,shell=True)
return 0
#threads = []
for round in range(1, 1600):
pool = multiprocessing.Pool(processes = 10) #使用进程池
for th in range(10):
# th_name = "thread-" + str(th)
# threads.append(th_name) #添加线程到线程列表
# threading.Thread(target = dd_test, args = (round, th), name = th_name).start() #创建多线程任务
pool.apply_async(dd_test, (round, th))
pool.close()
pool.join()
#等待线程完成
# for t in threads:
# t.join()
if mds_stat(round) == 0:
subprocess.call("zbkc -s",shell=True)
break
❷ python怎么多进程
需要借用库,来进行多进程,
threading
可以去了解熟悉这个库,这个可以实现多进程并发
❸ Python多进程运行——Multiprocessing基础教程2
上篇文章简单介绍了multiprocessing模块,本文将要介绍进程之间的数据共享和信息传递的概念。
在多进程处理中,所有新创建的进程都会有这两个特点:独立运行,有自己的内存空间。
我们来举个例子展示一下:
这个程序的输出结果是:
在上面的程序中我们尝试在两个地方打印全局列表result的内容:
我们再用一张图来帮助理解记忆不同进程间的数据关系:
如果程序需要在不同的进程之间共享一些数据的话,该怎么做呢?不用担心,multiprocessing模块提供了Array对象和Value对象,用来在进程之间共享数据。
所谓Array对象和Value对象分别是指从共享内存中分配的ctypes数组和对象。我们直接来看一个例子,展示如何用Array对象和Value对象在进程之间共享数据:
程序输出的结果如下:
成功了!主程序和p1进程输出了同样的结果,说明程序中确实完成了不同进程间的数据共享。那么我们来详细看一下上面的程序做了什么:
在主程序中我们首先创建了一个Array对象:
向这个对象输入的第一个参数是数据类型:i表示整数,d代表浮点数。第二个参数是数组的大小,在这个例子中我们创建了包含4个元素的数组。
类似的,我们创建了一个Value对象:
我们只对Value对象输入了一个参数,那就是数据类型,与上述的方法一致。当然,我们还可以对其指定一个初始值(比如10),就像这样:
随后,我们在创建进程对象时,将刚创建好的两个对象:result和square_sum作为参数输入给进程:
在函数中result元素通过索引进行数组赋值,square_sum通过 value 属性进行赋值。
注意:为了完整打印result数组的结果,需要使用 result[:] 进行打印,而square_sum也需要使用 value 属性进行打印:
每当python程序启动时,同时也会启动一个服务器进程。随后,只要我们需要生成一个新进程,父进程就会连接到服务器并请求它派生一个新进程。这个服务器进程可以保存Python对象,并允许其他进程使用代理来操作它们。
multiprocessing模块提供了能够控制服务器进程的Manager类。所以,Manager类也提供了一种创建可以在不同流程之间共享的数据的方法。
服务器进程管理器比使用共享内存对象更灵活,因为它们可以支持任意对象类型,如列表、字典、队列、值、数组等。此外,单个管理器可以由网络上不同计算机上的进程共享。
但是,服务器进程管理器的速度比使用共享内存要慢。
让我们来看一个例子:
这个程序的输出结果是:
我们来理解一下这个程序做了什么:首先我们创建了一个manager对象
在with语句下的所有行,都是在manager对象的范围内的。接下来我们使用这个manager对象创建了列表(类似的,我们还可以用 manager.dict() 创建字典)。
最后我们创建了进程p1(用于在records列表中插入一条新的record)和p2(将records打印出来),并将records作为参数进行传递。
服务器进程的概念再次用下图总结一下:
为了能使多个流程能够正常工作,常常需要在它们之间进行一些通信,以便能够划分工作并汇总最后的结果。multiprocessing模块支持进程之间的两种通信通道:Queue和Pipe。
使用队列来回处理多进程之间的通信是一种比较简单的方法。任何Python对象都可以使用队列进行传递。我们来看一个例子:
上面这个程序的输出结果是:
我们来看一下上面这个程序到底做了什么。首先我们创建了一个Queue对象:
然后,将这个空的Queue对象输入square_list函数。该函数会将列表中的数平方,再使用 put() 方法放入队列中:
随后使用 get() 方法,将q打印出来,直至q重新称为一个空的Queue对象:
我们还是用一张图来帮助理解记忆:
一个Pipe对象只能有两个端点。因此,当进程只需要双向通信时,它会比Queue对象更好用。
multiprocessing模块提供了 Pipe() 函数,该函数返回由管道连接的一对连接对象。 Pipe() 返回的两个连接对象分别表示管道的两端。每个连接对象都有 send() 和 recv() 方法。
我们来看一个例子:
上面这个程序的输出结果是:
我们还是来看一下这个程序到底做了什么。首先创建了一个Pipe对象:
与上文说的一样,该对象返回了一对管道两端的两个连接对象。然后使用 send() 方法和 recv() 方法进行信息的传递。就这么简单。在上面的程序中,我们从一端向另一端发送一串消息。在另一端,我们收到消息,并在收到END消息时退出。
要注意的是,如果两个进程(或线程)同时尝试从管道的同一端读取或写入管道中的数据,则管道中的数据可能会损坏。不过不同的进程同时使用管道的两端是没有问题的。还要注意,Queue对象在进程之间进行了适当的同步,但代价是增加了计算复杂度。因此,Queue对象对于线程和进程是相对安全的。
最后我们还是用一张图来示意:
Python的multiprocessing模块还剩最后一篇文章:多进程的同步与池化
敬请期待啦!
❹ python 多进程和多线程配合
由于python的多线程中存在PIL锁,因此python的多线程不能利用多核,那么,由于现在的计算机是多核的,就不能充分利用计算机的多核资源。但是python中的多进程是可以跑在不同的cpu上的。因此,尝试了多进程+多线程的方式,来做一个任务。比如:从中科大的镜像源中下载多个rpm包。
#!/usr/bin/pythonimport reimport commandsimport timeimport multiprocessingimport threadingdef download_image(url):
print '*****the %s rpm begin to download *******' % url
commands.getoutput('wget %s' % url)def get_rpm_url_list(url):
commands.getoutput('wget %s' % url)
rpm_info_str = open('index.html').read()
regu_mate = '(?<=<a href=")(.*?)(?=">)'
rpm_list = re.findall(regu_mate, rpm_info_str)
rpm_url_list = [url + rpm_name for rpm_name in rpm_list] print 'the count of rpm list is: ', len(rpm_url_list) return rpm_url_
def multi_thread(rpm_url_list):
threads = [] # url = 'https://mirrors.ustc.e.cn/centos/7/os/x86_64/Packages/'
# rpm_url_list = get_rpm_url_list(url)
for index in range(len(rpm_url_list)): print 'rpm_url is:', rpm_url_list[index]
one_thread = threading.Thread(target=download_image, args=(rpm_url_list[index],))
threads.append(one_thread)
thread_num = 5 # set threading pool, you have put 4 threads in it
while 1:
count = min(thread_num, len(threads)) print '**********count*********', count ###25,25,...6707%25
res = [] for index in range(count):
x = threads.pop()
res.append(x) for thread_index in res:
thread_index.start() for j in res:
j.join() if not threads:
def multi_process(rpm_url_list):
# process num at the same time is 4
process = []
rpm_url_group_0 = []
rpm_url_group_1 = []
rpm_url_group_2 = []
rpm_url_group_3 = [] for index in range(len(rpm_url_list)): if index % 4 == 0:
rpm_url_group_0.append(rpm_url_list[index]) elif index % 4 == 1:
rpm_url_group_1.append(rpm_url_list[index]) elif index % 4 == 2:
rpm_url_group_2.append(rpm_url_list[index]) elif index % 4 == 3:
rpm_url_group_3.append(rpm_url_list[index])
rpm_url_groups = [rpm_url_group_0, rpm_url_group_1, rpm_url_group_2, rpm_url_group_3] for each_rpm_group in rpm_url_groups:
each_process = multiprocessing.Process(target = multi_thread, args = (each_rpm_group,))
process.append(each_process) for one_process in process:
one_process.start() for one_process in process:
one_process.join()# for each_url in rpm_url_list:# print '*****the %s rpm begin to download *******' %each_url## commands.getoutput('wget %s' %each_url)
def main():
url = 'https://mirrors.ustc.e.cn/centos/7/os/x86_64/Packages/'
url_paas = 'http://mirrors.ustc.e.cn/centos/7.3.1611/paas/x86_64/openshift-origin/'
url_paas2 ='http://mirrors.ustc.e.cn/fedora/development/26/Server/x86_64/os/Packages/u/'
start_time = time.time()
rpm_list = get_rpm_url_list(url_paas) print multi_process(rpm_list) # print multi_thread(rpm_list)
#print multi_process()
# print multi_thread(rpm_list)
# for index in range(len(rpm_list)):
# print 'rpm_url is:', rpm_list[index]
end_time = time.time() print 'the download time is:', end_time - start_timeprint main()123456789101112131415161718
代码的功能主要是这样的:
main()方法中调用get_rpm_url_list(base_url)方法,获取要下载的每个rpm包的具体的url地址。其中base_url即中科大基础的镜像源的地址,比如:http://mirrors.ustc.e.cn/centos/7.3.1611/paas/x86_64/openshift-origin/,这个地址下有几十个rpm包,get_rpm_url_list方法将每个rpm包的url地址拼出来并返回。
multi_process(rpm_url_list)启动多进程方法,在该方法中,会调用多线程方法。该方法启动4个多进程,将上面方法得到的rpm包的url地址进行分组,分成4组,然后每一个组中的rpm包再最后由不同的线程去执行。从而达到了多进程+多线程的配合使用。
代码还有需要改进的地方,比如多进程启动的进程个数和rpm包的url地址分组是硬编码,这个还需要改进,毕竟,不同的机器,适合同时启动的进程个数是不同的。
❺ python可以多进程吗
想要充分利用多核CPU资源,Python中大部分情况下都需要使用多进程,Python中提供了multiprocessing这个包实现多进程。multiprocessing支持子进程、进程间的同步与通信,提供了Process、Queue、Pipe、Lock等组件。
开辟子进程
multiprocessing中提供了Process类来生成进程实例
Process([group [, target [, name [, args [, kwargs]]]]])
group分组,实际上不使用
target表示调用对象,你可以传入方法的名字
args表示给调用对象以元组的形式提供参数,比如target是函数a,他有两个参数m,n,那么该参数为args=(m, n)即可
kwargs表示调用对象的字典
name是别名,相当于给这个进程取一个名字
先来个小例子:
# -*- coding:utf-8 -*-
from multiprocessing import Process, Pool
import os
import time
def run_proc(wTime):
n = 0
while n < 3:
print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime()) #获取当前进程号和正在运行是的时间
time.sleep(wTime) #等待(休眠)
n += 1
if __name__ == "__main__":
p = Process(target=run_proc, args=(2,)) #申请子进程
p.start() #运行进程
print "Parent process run. subProcess is ", p.pid
print "Parent process end,{0}".format(time.ctime())
运行结果:
Parent process run. subProcess is 30196
Parent process end,Mon Mar 27 11:20:21 2017
subProcess 30196 run, Mon Mar 27 11:20:21 2017
subProcess 30196 run, Mon Mar 27 11:20:23 2017
subProcess 30196 run, Mon Mar 27 11:20:25 2017
根据运行结果可知,父进程运行结束后子进程仍然还在运行,这可能造成僵尸( zombie)进程。
通常情况下,当子进程终结时,它会通知父进程,清空自己所占据的内存,并在内核里留下自己的退出信息。父进程在得知子进程终结时,会从内核中取出子进程的退出信息。但是,如果父进程早于子进程终结,这可能造成子进程的退出信息滞留在内核中,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。
有什么办法可以避免僵尸进程呢?
这里介绍进程的一个属性 deamon,当其值为TRUE时,其父进程结束,该进程也直接终止运行(即使还没运行完)。
所以给上面的程序加上p.deamon = true,看看效果。
# -*- coding:utf-8 -*-
from multiprocessing import Process, Pool
import os
import time
def run_proc(wTime):
n = 0
while n < 3:
print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())
time.sleep(wTime)
n += 1
if __name__ == "__main__":
p = Process(target=run_proc, args=(2,))
p.daemon = True #加入daemon
p.start()
print "Parent process run. subProcess is ", p.pid
print "Parent process end,{0}".format(time.ctime())
执行结果:
Parent process run. subProcess is 31856
Parent process end,Mon Mar 27 11:40:10 2017
这是问题又来了,子进程并没有执行完,这不是所期望的结果。有没办法将子进程执行完后才让父进程结束呢?
这里引入p.join()方法,它使子进程执行结束后,父进程才执行之后的代码
# -*- coding:utf-8 -*-
from multiprocessing import Process, Pool
import os
import time
def run_proc(wTime):
n = 0
while n < 3:
print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())
time.sleep(wTime)
n += 1
if __name__ == "__main__":
p = Process(target=run_proc, args=(2,))
p.daemon = True
p.start()
p.join() #加入join方法
print "Parent process run. subProcess is ", p.pid
print "Parent process end,{0}".format(time.ctime())
执行结果:
subProcess 32076 run, Mon Mar 27 11:46:07 2017
subProcess 32076 run, Mon Mar 27 11:46:09 2017
subProcess 32076 run, Mon Mar 27 11:46:11 2017
Parent process run. subProcess is 32076
Parent process end,Mon Mar 27 11:46:13 2017
这样所有的进程就能顺利的执行了。
❻ python 多进程的顺序问题
因为进程池一次只能运行4个进程,0,1,2,3是四个进程同时执行,那么4只能等待。当进程池中任意一个进程结束后,4立即执行,所以在0结束后4开始执行,接着1,2,3陆续结束,4最后结束。
❼ 为什么Python中的NumPy会多进程并行加载数据,而且返回的结果却是相同的
明敏 发自 凹非寺
量子位 报道 | 公众号 QbitAI
到底是怎样的一个bug,能让95%的Pytorch库中招,就连特斯拉AI总监深受困扰?
还别说,这个bug虽小,但有够“狡猾”的。
这就是最近Reddit上热议的一个话题,是一位网友在使用再平常不过的Pytorch+Numpy组合时发现。
最主要的是,在代码能够跑通的情况下,它甚至还会影响模型的准确率!
除此之外,网友热议的另外一个点,竟然是:
而是它到底算不算一个bug?
这究竟是怎么一回事?
事情的起因是一位网友发现,在PyTorch中用NumPy来生成随机数时,受到数据预处理的限制,会多进程并行加载数据,但最后每个进程返回的随机数却是相同的。
他还举出例子证实了自己的说法。
如下是一个示例数据集,它会返回三个元素的随机向量。这里采用的批量大小分别为2,工作进程为4个。
然后神奇的事情发生了:每个进程返回的随机数都是一样的。
这个结果会着实让人有点一头雾水,就好像数学应用题求小明走一段路程需要花费多少时间,而你却算出来了负数。
发现了问题后,这位网友还在GitHub上下载了超过10万个PyTorch库,用同样的方法产生随机数。
结果更加令人震惊:居然有超过95%的库都受到这个问题的困扰!
这其中不乏PyTorch的官方教程和OpenAI的代码,连特斯拉AI总监Karpathy也承认自己“被坑过”!
但有一说一,这个bug想要解决也不难:只需要在每个epoch都重新设置seed,或者用python内置的随机数生成器就可以避免这个问题。
到底是不是bug?
如果这个问题已经可以解决,为什么还会引起如此大的讨论呢?
因为网友们的重点已经上升到了“哲学”层面:
这到底是不是一个bug?
在Reddit上有人认为:这不是一个bug。
虽然这个问题非常常见,但它并不算是一个bug,而是一个在调试时不可以忽略的点。
就是这个观点,激起了千层浪花,许多人都认为他忽略了问题的关键所在。
这不是产生伪随机数的问题,也不是numpy的问题,问题的核心是在于PyTorch中的DataLoader的实现
对于包含随机转换的数据加载pipeline,这意味着每个worker都将选择“相同”的转换。而现在NN中的许多数据加载pipeline,都使用某种类型的随机转换来进行数据增强,所以不重新初始化可能是一个预设。
另一位网友也表示这个bug其实是在预设程序下运行才出现的,应该向更多用户指出来。
并且95%以上的Pytorch库受此困扰,也绝不是危言耸听。
有人就分享出了自己此前的惨痛经历:
我认识到这一点是之前跑了许多进程来创建数据集时,然而发现其中一半的数据是重复的,之后花了很长的时间才发现哪里出了问题。
也有用户补充说,如果 95% 以上的用户使用时出现错误,那么代码就是错的。
顺便一提,这提供了Karpathy定律的另一个例子:即使你搞砸了一些非常基本代码,“neural nets want to work”。
你有踩过PyTorch的坑吗?
如上的bug并不是偶然,随着用PyTorch的人越来越多,被发现的bug也就越来越多,某乎上还有PyTorch的坑之总结,被浏览量高达49w。
其中从向量、函数到model.train(),无论是真bug还是自己出了bug,大家的血泪史还真的是各有千秋。
所以,关于PyTorch你可以分享的经验血泪史吗?
欢迎评论区留言讨论~
参考链接:
[1]https://tanelp.github.io/posts/a-bug-that-plagues-thousands-of-open-source-ml-projects/
[2]https://www.reddit.com/r/MachineLearning/comments/mocpgj/p_using_pytorch_numpy_a_bug_that_plagues/
[3]https://www.hu.com/question/67209417/answer/866488638
— 完 —
❽ 如何使用Python实现多进程编程
1.Process
创建进程的类:Process([group[,target[,name[,args[,kwargs]]]]]),target表示调用对象,args表示调用对象的位置参数元组。kwargs表示调用对象的字典。name为别名。group实质上不使用。
方法:is_alive()、join([timeout])、run()、start()、terminate()。其中,Process以start()启动某个进程。
属性:authkey、daemon(要通过start()设置)、exitcode(进程在运行时为None、如果为–N,表示被信号N结束)、name、pid。其中daemon是父进程终止后自动终止,且自己不能产生新进程,必须在start()之前设置。
例1.1:创建函数并将其作为单个进程
importmultiprocessing
importtime
defworker(interval):
n=5
whilen>0:
print("Thetimeis{0}".format(time.ctime()))
time.sleep(interval)
n-=1
if__name__=="__main__":
p=multiprocessing.Process(target=worker,args=(3,))
p.start()
print"p.pid:",p.pid
print"p.name:",p.name
print"p.is_alive:",p.is_alive()
结果
12345678p.pid:8736p.name:Process-1p.is_alive:TrueThetimeisTueApr2120:55:122015ThetimeisTueApr2120:55:152015ThetimeisTueApr2120:55:182015ThetimeisTueApr2120:55:212015ThetimeisTueApr2120:55:242015
例1.2:创建函数并将其作为多个进程
importmultiprocessing
importtime
defworker_1(interval):
print"worker_1"
time.sleep(interval)
print"endworker_1"
defworker_2(interval):
print"worker_2"
time.sleep(interval)
print"endworker_2"
defworker_3(interval):
print"worker_3"
time.sleep(interval)
print"endworker_3"
if__name__=="__main__":
p1=multiprocessing.Process(target=worker_1,args=(2,))
p2=multiprocessing.Process(target=worker_2,args=(3,))
p3=multiprocessing.Process(target=worker_3,args=(4,))
p1.start()
p2.start()
p3.start()
print("ThenumberofCPUis:"+str(multiprocessing.cpu_count()))
forpinmultiprocessing.active_children():
print("childp.name:"+p.name+" p.id"+str(p.pid))
print"END!!!!!!!!!!!!!!!!!"
结果
1234567891011ThenumberofCPUis:4childp.name:Process-3p.id7992childp.name:Process-2p.id4204childp.name:Process-1p.id6380END!!!!!!!!!!!!!!!!!worker_1worker_3worker_2endworker_1endworker_2endworker_3
例1.3:将进程定义为类
importmultiprocessing
importtime
classClockProcess(multiprocessing.Process):
def__init__(self,interval):
multiprocessing.Process.__init__(self)
self.interval=interval
defrun(self):
n=5
whilen>0:
print("thetimeis{0}".format(time.ctime()))
time.sleep(self.interval)
n-=1
if__name__=='__main__':
p=ClockProcess(3)
p.start()
注:进程p调用start()时,自动调用run()
结果
12345thetimeisTueApr2120:31:302015thetimeisTueApr2120:31:332015thetimeisTueApr2120:31:362015thetimeisTueApr2120:31:392015thetimeisTueApr2120:31:422015
❾ python能实现并行吗
Python可以实现并行,Python可以用多进程来实现并行。
进程与线程的定义:
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
进程与线程的联系:
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
更多Python知识,请关注:Python自学网!!
❿ python中多进程和多线程的区别
什么是线程、进程?
进程(process)与线程(thread)是操作系统的基本概念,它们比较抽象,不容易掌握。
关于这两者,最经典的一句话就是“进程是资源分配的最小单位,线程是CPU调度的最小单位”,线程是程序中一个单一的顺序控制流程,进程内一个相对独立的、可调度的执行单元,是系统独立调度和分配CPU的基本单位指运行中的程序的调度单位,在单个程序中同时运行多个线程完成不同的工作,称为多线程。
进程与线程的区别是什么?
进程是资源分配的基本单位,所有与该进程有关的资源,都被记录在进程控制块PCB中,以表示该进程拥有这些资源或正在使用它们,另外,进程也是抢占处理机的调度单位,它拥有一个完整的虚拟地址空间,当进程发生调度时,不同的进程拥有不同的虚拟地址空间,而同一进程内的不同线程共享同一地址空间。
与进程相对应的,线程与资源分配无关,它属于某一个进程,并与进程内的其他线程一起共享进程的资源,线程只由相关堆栈(系统栈或用户栈)寄存器和线程控制表TCB组成,寄存器可被用来存储线程内的局部变量,但不能存储其他线程的相关变量。
通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。
由于线程比进程更小,基本上不拥有系统资源,所以对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度,从而显着提高系统资源的利用率和吞吐量。
因而近年来推出的通用操作系统都引入了线程,以便进一步提高系统的并发性,并把它视为现代操作系统的一个重要指标。