前言Process,一个新词,有些人可能不理解,它是系统中一个运行程序的载体,这个程序可以有单个或多个进程,一般来说,Processes根据系统中的CPU核数进行分配和设置。我们可以查看系统中的进程:可以看到,360浏览器是真实存在的。有这么多的过程。当然,您可以通过这种方式非常清楚地看到它们。进程线程使用:通过任务管理器中的资源监视器,是不是很厉害,哈哈哈。说完这些,再来说说用法。1、基本的使用流程能做什么,是我们要慎重考虑的事情。我们都知道一个程序在运行的时候会创建进程,所以在程序创建这些进程的时候,为了让它们更加有序的工作,还必须加入线程。那么在一个进程中就会有多个线程一起工作,但是进程不能创建太多,否则会消耗资源,除非你是开发一个大型系统。那么,让我们现在创建一个流程。一、创建进程1、创建进程之前,我们先导入进程的模块,代码如下:importmultiprocessasmm.Process(target,args)其实这种写法是错误的,就像bs4中的BeautifulSoup,你想先importbs4,再引入BeautifulSoup是不行的,必须这样:frommultiprocessingimportProcessProcess(group,target,args,kwargs,name)group:usergrouptarget:callfunctionargs:parameterancestorkwargs:parameterdictionaryname:子进程名可以看到进程和线程的用法基本类似,只是名称和作用不同。并且还有很多其他优秀的方法:#返回当前进程中存活的子进程列表。调用此方法具有“等待”已结束进程的副作用。multiprocessing.active_children()#返回系统中的CPU数量。multiprocessing.cpu_count()2.创建单进程函数的返回值从上面的参数可以知道,和线程基本一样。#启动进程,在进程中调用run()方法。start()#进程活动的方法run()#强行终止进程,不做任何清理操作。如果在终止前创建了子进程,则子进程被强制终止后成为僵尸进程;如果进程还持有锁,则不会释放,造成死锁。terminate()#判断一个进程是否存活,存活则返回True,否则返回False。is_alive()主线程等待子线程终止。timeout是一个可选的超时时间;需要强调的是:p.join只能加入start启动的进程,不能加入run启动的进程。join([timeout])#设置进程为后台守护进程;当进程的父进程终止时,进程也终止,进程不能创建子进程,必须在start()daemon#processname之前设置该属性。name#processpid,pid#child进程的退出码只能在启动后生成。如果进程没有终止,这将是None,负值-N表示子进程被信号N终止。exitcode#Process身份验证,默认是由os.urandom()随机生成的字符串。验证网络进程连接是否正确authkey#系统对象的数字句柄,当进程结束时将变为“就绪”。sentinel#killprocesskill()#关闭进程close()请注意:在创建进程的时候,一定要加上如下语句:if__name__=='__main__':这样,我们就实现了一个关于进程的程序.另外,我们也可以通过继承进程类来实现:可以说我们每创建一个进程,它都会有一个ID来标记它,下面这种情况:3.创建多个进程和单个进程往往是还不够,我们只需要创建一个多进程,多进程的创建方法也很简单,加一层循环即可:这样就可以轻松创建多进程任务,而且速度比以前快了.4.进程池进程池的设计初衷是为了方便我们更有效地利用资源,避免浪费。如果任务负载大,多核一起帮忙。少的话,就只开一两个核心。我们看一下实现过程:首先导入包:frommultiprocessingimportPoolimportmultiprocessingasm进程池的安装包是Pool,然后我们看一下它的CPU核心数:num=m.cpu_count()#CPU核心数然后我们创建一个进程池:pool=multiprocessing。Pool(num)进程池中也有很多方法供我们使用:apply(func,args,kwargs)同步执行(serial)阻塞apply_async(func,args,kwargs)异步执行(parallel)非阻塞terminate()强制终止进程,不处理未完成的任务。join()主进程阻塞,等待子进程退出。必须在close或terminate()之后使用close()等待所有进程结束才关闭进程池map(func,iterable,chunksize=int)映射函数的并行版本,一直阻塞直到得到结果#返回一个可以用来获取结果对象,回调函数要立即执行,否则负责处理结果的线程会被阻塞只是迭代器返回的结果是任意的imap_unordered(func,iterable,chunksize)#类似于map(),但iterable中的每一项都会被解包并用作函数参数。starmap(func,iterable,chunksize)我们可以为此创建同步和异步程序。如果你对此感兴趣,对于爬虫来说是一个非常不错的选择。较小的爬虫适合同步,较大的爬虫更适合异步效果。很多人不理解异步和同步。其实同步和异步就是串行和并行。串行和并行只是串行和并行。让我们看一下以下示例:1.串行2.并行。可以看出只是参数变化,其他类似。我们已经获取到当前进程的pid并打印出来了。5、Lock虽然异步编程多进程给我们带来了方便,但是进程启动后是不可控的,我们需要控制它,让它做我们认为有意义的事情。这个时候我们就需要加锁了。锁和线程一样:先导入进程锁的模块:frommultiprocessingimportLock然后我们创建一个关于锁的程序:可以看到加锁的过程比较顺利,和多线程一样简单,但是相对来说,速度会更快更慢。既然有Lock,就一定有RLock。在python中,进程和线程的很多用法是一样的,锁也是。我们可以改成RLock,下面是一个可重入锁,也就是可以递归:importtimelock1=RLock()lock2=RLock()s=time.time()defjc(num):lock1.acquire()lock2.acquire()print('start')print(m.current_process().pid,'run----',str(num))lock1.释放()锁2。release()打印('end')if__name__=='__main__':aa=[]foryinrange(12):pp=Process(target=jc,args=(y,))pp.start()aa.append(pp)forxinaa:x.join()e=time.time()print(e-s)6.进程间通信1.事件用于进程间通信。方法和线程完全一样。这里举个小栗子,就不详细说了。不明白的可以看我之前关于线程的文章。文章,今天要讲的是其他进程间通信方式,请看下面:importtimee=Event()defmain(num):whileTrue:ifnum<5:e.clear()#clearsignalflagprint('clear')ifnum>=5:e.wait(timeout=1)#等待信号标志为真e.set()print('start')ifnum==10:e.wait(timeout=3)e.clear()print('exit')breaknum+=1time.sleep(2)if__name__=='__main__':foryinrange(10):pp=Process(target=main,args=(y,))pp.start()pp.join()二、管道传递消息管道模块初始化后返回两个参数,一个是发送者,一个是接收者。它有一个参数可以设置模式为全双工或者半双工,全双工发送和接收,半双工只接收或者只发送,先了解一下它的方法:p1,p2=m.Pipe(duplex=bool)#设置是否全双工,返回两个连接对象p1.send()#sendp2.recv()#receivep1.close()#关闭连接p1.fileno()#返回使用的整型文件描述符连接p1.poll([超时])#如果连接上的数据可用,返回True,超时指定最大等待时间p2.recv_bytes([maxlength])#接收最大字节数p1.send_bytes([maxlength])#发送最大字节数bytes#Receive一个完整的字节消息,并保存在buffer对象中,offset指定消息放置的地方在buffer中的字节位移。p2.recv_bytes_into(buffer[,offset])先接收再发送,其实我们可以用锁来控制它的启动,可以让它边接收边发送。3.队列队列与其他队列不同的是,它采用了插入和删除的方法。我们来看一下:deffd(a):foryinrange(10):a.put(y)#Insertdataprint('insert:',str(y))defdf(b):whileTrue:aa=b.get(True)#删除数据print('Release:',str(aa))if__name__=='__main__':q=Queue()ff=Process(target=fd,args=(q,))dd=Process(target=df,args=(q,))ff.start()#开始运行dd.start()dd.terminate()#关闭ff.join()上面说的队列主要用于多进程队列,还有进程池队列,在Manager模块中。7、信号量和线程完全一样,这里就不多说了,看下面的例子:s=Semaphore(3)s.acquire()print(s.get_value())s.release()print(s.get_value())print(s.get_value())s.release()print(s.get_value())s.release()output:23348数据共享共享数据类型可以直接通过设置流程模块:数值类型:m.Value()数组:m.Array()字典类型:m.dict()列表类型:m.list()也可以通过流程的Manager模块实现:Manager().dict()Manager.list()下面我们来举例说明一下:可以看到我们已经成功的向其中添加了数据,形成了数据共享。2.小??结通过流程的描述,相信大家此时此刻已经对流程有了深刻的理解。我突然想起一件事,那就是大家在学习的时候可能会上网查资料、搜索。那我建议你专心看我的文章。是的,因为据我所知,那些都是错误的,而且更让我不解的是代码明明是错误的,执行效果却是正确的,这让我百思不得其解,哈哈哈。
