发布网友 发布时间:2024-09-29 00:47
共1个回答
热心网友 时间:2024-10-01 19:59
导读:今天首席CTO笔记来给各位分享关于python可以有多少个子进程的相关内容,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
python多线程和多进程的区别有哪些python多线程和多进程的区别有七种:
1、多线程可以共享全局变量,多进程不能。
2、多线程中,所有子线程的进程号相同;多进程中,不同的子进程进程号不同。
3、线程共享内存空间;进程的内存是独立的。
4、同一个进程的线程之间可以直接交流;两个进程想通信,必须通过一个中间代理来实现。
5、创建新线程很简单;创建新进程需要对其父进程进行一次克隆。
6、一个线程可以控制和操作同一进程里的其他线程;但是进程只能操作子进程。
7、两者最大的不同在于:在多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响;而多线程中,所有变量都由所有线程共享。
更多Python知识,请关注:Python自学网!!
pythonprocess最多能多少个进程由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。
Python提供了非常好用的多进程包multiprocessing,只需要定义一个函数,Python会完成其他所有事情。借助这个包,可以轻松完成从单进程到并发执行的转换。
multiprocessing支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。
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-*-
frommultiprocessingimportProcess,Pool
importos
importtime
defrun_proc(wTime):
n=0
whilen3:
print"subProcess%srun,"%os.getpid(),"{0}".format(time.ctime())#获取当前进程号和正在运行是的时间
time.sleep(wTime)#等待(休眠)
n+=1
if__name__=="__main__":
p=Process(target=run_proc,args=(2,))#申请子进程
p.start()#运行进程
print"Parentprocessrun.subProcessis",p.pid
print"Parentprocessend,{0}".format(time.ctime())
运行结果:
Parentprocessrun.subProcessis30196
Parentprocessend,MonMar2711:20:212017
subProcess30196run,MonMar2711:20:212017
subProcess30196run,MonMar2711:20:232017
subProcess30196run,MonMar2711:20:252017
根据运行结果可知,父进程运行结束后子进程仍然还在运行,这可能造成僵尸(zombie)进程。
通常情况下,当子进程终结时,它会通知父进程,清空自己所占据的内存,并在内核里留下自己的退出信息。父进程在得知子进程终结时,会从内核中取出子进程的退出信息。但是,如果父进程早于子进程终结,这可能造成子进程的退出信息滞留在内核中,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。
有什么办法可以避免僵尸进程呢?
这里介绍进程的一个属性deamon,当其值为TRUE时,其父进程结束,该进程也直接终止运行(即使还没运行完)。
所以给上面的程序加上p.deamon=true,看看效果。
#-*-coding:utf-8-*-
frommultiprocessingimportProcess,Pool
importos
importtime
defrun_proc(wTime):
n=0
whilen3:
print"subProcess%srun,"%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"Parentprocessrun.subProcessis",p.pid
print"Parentprocessend,{0}".format(time.ctime())
执行结果:
Parentprocessrun.subProcessis31856
Parentprocessend,MonMar2711:40:102017
这是问题又来了,子进程并没有执行完,这不是所期望的结果。有没办法将子进程执行完后才让父进程结束呢?
这里引入p.join()方法,它使子进程执行结束后,父进程才执行之后的代码
#-*-coding:utf-8-*-
frommultiprocessingimportProcess,Pool
importos
importtime
defrun_proc(wTime):
n=0
whilen3:
print"subProcess%srun,"%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"Parentprocessrun.subProcessis",p.pid
print"Parentprocessend,{0}".format(time.ctime())
执行结果:
subProcess32076run,MonMar2711:46:072017
subProcess32076run,MonMar2711:46:092017
subProcess32076run,MonMar2711:46:112017
Parentprocessrun.subProcessis32076
Parentprocessend,MonMar2711:46:132017
这样所有的进程就能顺利的执行了。
python多进程基于官方文档:
日乐购,刚才看到的一个博客,写的都不太对,还是基于官方的比较稳妥
我就是喜欢抄官方的,哈哈
通常我们使用Process实例化一个进程,并调用他的start()方法启动它。
这种方法和Thread是一样的。
上图中,我写了p.join()所以主进程是等待子进程执行完后,才执行print("运行结束")
否则就是反过来了(这个不一定,看你的语句了,顺序其实是随机的)例如:
主进加个sleep
所以不加join(),其实子进程和主进程是各干各的,谁也不等谁。都执行完后,文件运行就结束了
上面我们用了os.getpid()和os.getppid()获取当前进程,和父进程的id
下面就讲一下,这两个函数的用法:
os.getpid()
返回当前进程的id
os.getppid()
返回父进程的id。父进程退出后,unix返回初始化进程(1)中的一个
windows返回相同的id(可能被其他进程使用了)
这也就解释了,为啥我上面的程序运行多次,第一次打印的parentid都是14212了。
而子进程的父级processid是调用他的那个进程的id:1940
视频笔记:
多进程:使用大致方法:
参考:进程通信(pipe和queue)
pool.map(函数可以有return也可以共享内存或queue)结果直接是个列表
poll.apply_async()(同map,只不过是一个进程,返回结果用xx.get()获得)
报错:
参考:
把pool=Pool()放到ifname=="main":下面初始化搞定。
结果:
这个肯定有解释的
测试多进程计算效果:
进程池运行:
结果:
普通计算:
我们同样传入1210三个参数测试:
其实对比下来开始快了一半的;
我们把循环里的数字去掉一个0;
单进程:
多进程:
两次测试单进程/进程池分别为0.669和0.772几乎成正比的。
问题二:
视图:
post视图里面
Music类:
直接报错:
写在类里面也在函数里用self.pool调用也不行,也是相同的错误。
最后把pool=Pool直接写在search函数里面,奇迹出现了:
前台也能显示搜索的音乐结果了
总结一点,进程这个东西,最好写在直接运行的函数里面,而不是一个函数跳来跳去。因为最后可能是在子进程的子进程运行的,这是不许的,会报错。
还有一点,多进程运行的函数对象,不能是lambda函数。也许lambda虚拟,在内存??
使用pool.map子进程函数报错,导致整个pool挂了:
参考:
主要你要,对函数内部捕获错误,而不能让异常抛出就可以了。
关于map传多个函数参数
我一开始,就是正常思维,多个参数,搞个元祖,让参数一一对应不就行了:
报错:
参考:
普通的process当让可以穿多个参数,map却不知道咋传的。
apply_async和map一样,不知道咋传的。
最简单的方法:
使用starmap而不是map
结果:
子进程结束
1.8399453163146973
成功拿到结果了
关于map和starmap不同的地方看源码:
关于apply_async(),我没找到多参数的方法,大不了用一个迭代的starmap实现。哈哈
关于上面源码里面有itertools.starmap
itertools用法参考:
有个问题,多进程最好不要使用全部的cpu,因为这样可能影响其他任务,所以在进程池添加process参数指定,cpu个数:
上面就是预留了一个cpu干其他事的
后面直接使用Queue遇到这个问题:
解决:
Manager().Queue()代替Queue()
因为queue.get()是堵塞型的,所以可以提前判断是不是空的,以免堵塞进程。比如下面这样:
使用queue.empty()空为True
Python入门系列(十二)——GUI+多进程话说,python做图形界面并不明智,效率并不高。但在某些特殊需求下还是需要我们去使用,所以python拥有多个第三方库用以实现GUI,本章我们使用python基本模块tkinter进行学习,因为需求并不大,所以不做太多拓展。
继续改写上一章的IP查询系统(==,要玩烂了),首先略改下IpWhere.py以备调用~
然后使用tkinter模块进行图形界面的实现,调用预编译的IpWhere模块:
额,太丑了,但基本实现我们小小的需求,在以后的py学习中,我们再涉及其他的第三方模块,此处就当是入门了解吧。
十分抱歉把这么重要的内容放在最后,要不是大佬指点,此次学习可能就要错过多进程的问题了。
Unix系统提供了forx,python可借助os模块调用,从而实现多进程,然而windows系统并不具备,所以我们选择python内置的multiprocessing多进程模块进行学习。
首先我们借助直接调用多进程来改写下我们在多线程章节用到的例子!
显然,这么写实在太蠢了,如果我们的任务量巨大,这并不合适。所以我们引入了进程池的概念,使用进程池进行改写:
在此,我们可以看到所有进程是并发执行的,同样,我们在多线程章节就讲过,主进程的结束意味着程序退出,所以我们需要借助join()方法堵塞进程。
我们知道线程共享内存空间,而进程的内存是独立的,同一个进程的线程之间可以直接交流,也就带来了线程同步的苦恼,这个我们在多线程章节已经讲过了;而两个进程想通信,则必须通过一个中间代理来实现,即我们接下来的内容:进程间通信。
进程之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。我们接下来就以Queue的方式进行学习。
Queue.Queue是进程内非阻塞队列,multiprocess.Queue是跨进程通信队列,前者是各自私有,后者是各子进程共有。
还有一个在后者基础上进行封装的multiprocess.Manager.Queue()方法,如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到一条如下的错误信息:RuntimeError:Queueobjectsshouldonlybesharedbetweenprocessesthroughinheritance.
接下来我们就借助进程池来进行多进程操作的改写,感谢大佬一路辅导。
我们可以看到两个子线程先执行,然后一个子线程单独执行,此处有意而为之,让大家更清晰的了解队列的使用。期间有一处我们放弃使用jion()方法堵塞,而是自己写了个循环堵塞,大家根据自己习惯来就好。
话说,真的没人吐槽么?上面的例子从需求上来讲,完全就不需要多线程好不好!emmmm,我们来点实力拓展,写一个有智商的多线程脚本,顺便结合上一节的web来一个综合篇,随便找个现实需求吧!
emmm,比如我们来到当当网买书,搜一下我们想要的书籍,发现!!太多了!!真J2乱!!看不过来!!不想翻页!!直接告诉我哪个便宜、哪个牛逼好不好!!
简单看下这个url:
渗透测试ddsale=1page_index=2
其中ddsale参数代表当当自营,page_index代表页数,key代表搜索内容,我们本次的变量只有页数。
所以我们构造请求的url为:
'渗透测试ddsale=1page_index='+str(page)
如果修改的内容不使用str字符串转化,会收到如下报错:
TypeError:canonlyconcatenatestr(not"int")tostr
然后我们看一下页面内容的分布情况,本次我们关心卖什么书,卖多少钱?
对应的编写我们的正则匹配规则,当然了,有更简便的第三方库可以帮我们处理,但为了更好的形成流程性认识,我们这里依然使用正则。
我们对应我们需要的书籍名称和当前价格匹配如下:
atitle="(.*?)"ddclick=
spanclass="search_now_price"?(.*?)/span
那么,思路理清了,我们就开始使用多线程来写我们的小系统~
然后我们去查看一下我们的结果文件~
现在这个小系统具备的功能就是根据用户需要选择要检索的书籍,然后整理下名称和价格,开了10个线程,如果小伙伴pc给力的话可以继续加。简单的异常处理机制和界面交互,基本满足日常所需。
python多进程和多线程的区别进程是程序(软件,应用)的一个执行实例,每个运行中的程序,可以同时创建多个进程,但至少要有一个。每个进程都提供执行程序所需的所有资源,都有一个虚拟的地址空间、可执行的代码、操作系统的接口、安全的上下文(记录启动该进程的用户和权限等等)、唯一的进程ID、环境变量、优先级类、最小和最大的工作空间(内存空间)。进程可以包含线程,并且每个进程必须有至少一个线程。每个进程启动时都会最先产生一个线程,即主线程,然后主线程会再创建其他的子线程。
线程,有时被称为轻量级进程(LightweightProcess,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不独立拥有系统资源,但它可与同属一个进程的其它线程共享该进程所拥有的全部资源。每一个应用程序都至少有一个进程和一个线程。在单个程序中同时运行多个线程完成不同的被划分成一块一块的工作,称为多线程。
举个例子,某公司要生产一种产品,于是在生产基地建设了很多厂房,每个厂房内又有多条流水生产线。所有厂房配合将整个产品生产出来,单个厂房内的流水线负责生产所属厂房的产品部件,每个厂房都拥有自己的材料库,厂房内的生产线共享这些材料。公司要实现生产必须拥有至少一个厂房一条生产线。换成计算机的概念,那么这家公司就是应用程序,厂房就是应用程序的进程,生产线就是某个进程的一个线程。
线程的特点:
线程是一个executioncontext(执行上下文),即一个cpu执行时所需要的一串指令。假设你正在读一本书,没有读完,你想休息一下,但是你想在回来时继续先前的进度。有一个方法就是记下页数、行数与字数这三个数值,这些数值就是executioncontext。如果你的室友在你休息的时候,使用相同的方法读这本书。你和她只需要这三个数字记下来就可以在交替的时间共同阅读这本书了。
线程的工作方式与此类似。CPU会给你一个在同一时间能够做多个运算的幻觉,实际上它在每个运算上只花了极少的时间,本质上CPU同一时刻只能干一件事,所谓的多线程和并发处理只是假象。CPU能这样做是因为它有每个任务的executioncontext,就像你能够和你朋友共享同一本书一样。
进程与线程区别:
同一个进程中的线程共享同一内存空间,但进程之间的内存空间是独立的。
同一个进程中的所有线程的数据是共享的,但进程之间的数据是独立的。
对主线程的修改可能会影响其他线程的行为,但是父进程的修改(除了删除以外)不会影响其他子进程。
线程是一个上下文的执行指令,而进程则是与运算相关的一簇资源。
同一个进程的线程之间可以直接通信,但是进程之间的交流需要借助中间代理来实现。
创建新的线程很容易,但是创建新的进程需要对父进程做一次复制。
一个线程可以操作同一进程的其他线程,但是进程只能操作其子进程。
线程启动速度快,进程启动速度慢(但是两者运行速度没有可比性)。
由于现代cpu已经进入多核时代,并且主频也相对以往大幅提升,多线程和多进程编程已经成为主流。Python全面支持多线程和多进程编程,同时还支持协程。
结语:以上就是首席CTO笔记为大家介绍的关于python可以有多少个子进程的全部内容了,希望对大家有所帮助,如果你还想了解更多这方面的信息,记得收藏关注本站。