multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境
调用方法一:
import multiprocessing#多进程包 import time def visit(name): time.sleep(1) print('hello', name,time.ctime()) if __name__ == '__main__': p_list=[] for i in range(3): p = multiprocessing.Process(target=visit, args=('alvin',))#创建子进程对象 p_list.append(p) p.start()#开启进程 for i in p_list: p.join()#与线程意义先疼痛 print('end')
调用方法二:
class MyProcess(Process): def run(self): time.sleep(1) print ('hello', self.name,time.ctime()) if __name__ == '__main__': p_list=[] for i in range(3): p = MyProcess() p.start() p_list.append(p) for p in p_list: p.join() print('end')
一:pid
class progress(multiprocessing.Process): def run(self): time.sleep(2) print("process name",self.name) print("parent process id",os.getppid(),time.time()) print("process id",os.getpid(),time.time()) if __name__=="__main__": print("main process line") progress.run(progress) print("----------") t1=progress() t2=progress() t1.start() t2.start() #主进程的parent process id 33440 1550129555.0609472 #主进程的process id 21996 1550129555.0609472 #子进程 process name progress-1 parent process id 21996 1550129557.234302 process id 29496 1550129557.234302
二:方法与属性
-
is_alive():返回进程是否在运行。
-
join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。
-
start():进程准备就绪,等待CPU调度
-
run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。
- terminate():不管任务是否完成,立即停止工作进程
-
daemon:和线程的setDeamon功能一样
-
name:进程名字。
-
pid:进程号
一:进程队列queque
import multiprocessing,time def foo(parad): time.sleep(1) print("子进程队列id",id(parad)) parad.put("name") parad.put({"name":"alex"}) if __name__=="__main__": p_list=[] parad=multiprocessing.Queue()#创建一个进程队列 print("主进程队列",id(parad)) for i in range(3): progress=multiprocessing.Process(target=foo,args=(parad,)) progress.start() print(parad.get()) print(parad.get())
二:管道pipe
- pipe()函数返回一对通过一个双向管道链接的链接对象
- parent_conn, child_conn = multiprocessing.Pipe()#创建一个管道对象
- parent_conn.recv()#接收 parent_conn.send()#发数据
def foo(conn): time.sleep(1) conn.send("hellow father") print("子进程收:",conn.recv()) conn.close() if __name__=="__main__": parent_conn, child_conn = multiprocessing.Pipe()#创建一个管道对象 progress=multiprocessing.Process(target=foo,args=(child_conn,))#将管道一方传送到子进程 progress.start() print("主线程收:",parent_conn.recv())#接收数据 parent_conn.send("hellow son")#发送数据 progress.join() print("ending...")
- The two connection objects returned by
Pipe()
represent the two ends of the pipe. Each connection object hassend()
andrecv()
methods (among others). Note that data in a pipe may become corrupted if two processes (or threads) try to read from or write to the same end of the pipe at the same time. Of course there is no risk of corruption from processes using different ends of the pipe at the same time
三:manager
Queue和pipe只是实现了数据交互,并没实现数据共享,即一个进程去更改另一个进程的数据。
A manager object returned by Manager()
controls a server process which holds Python objects and allows other processes to manipulate them using proxies.
A manager returned by Manager()
will support types list
, dict
, Namespace
, Lock
, RLock
, Semaphore
, BoundedSemaphore
, Condition
, Event
, Barrier
, Queue
, Value
and Array
. For example:
def foo(dict,list,i,string): dict["name"]="tom" list[0]=5 list.append(i) string="i am tom" print("son process",id(dict),id(list)) if __name__=="__main__": with multiprocessing.Manager() as manager: dict=manager.dict({"name":"alex"}) list=manager.list([1,2,3,4]) string=manager.Value(value="i am alex",typecode=int) p_list=[] for i in range(2): progress=multiprocessing.Process(target=foo,args=(dict,list,i,string)) p_list.append(progress) progress.start() for i in p_list: i.join() print(dict) print(list) print(string) print("father process", id(dict), id(list))
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止
进程池中的方法:
- apply 从进程池里取一个进程并同步执行
- apply_async 从进程池里取出一个进程并异步执行
- terminate 立刻关闭进程池
- join 主进程等待所有子进程执行完毕,必须在close或terminete之后
- close 等待所有进程结束才关闭线程池
1 import multiprocessing,time,os 2 def foo(i): 3 time.sleep(1) 4 print(i,time.time()) 5 print("son",os.getpid())#17728 6 def success(arg): 7 print("success",os.getpid())#18340 8 def fail(arg): 9 print("falid") 10 if __name__ == '__main__': 11 print("main:",os.getpid())#18340 12 pool=multiprocessing.Pool() 13 lock=multiprocessing.Lock() 14 for i in range(20): 15 pool.apply_async(func=foo,args=(i,),callback=success,error_callback=fail) 16 #pool.apply(func=foo,args=(i,)) 17 pool.close() 18 pool.join() 19 print("ending....")
所谓协程又称为微线程,我们在进程在创建时, 需要耗费时间和cpu资源;在创建多线程时,也需要消耗时间和资源。利用多协程的运行过程中,始终只要一个线程, 不存在创建线程和销毁线程需要的时间; 也没有线程切换的开销, 任务需要开启线程数越多, 协程的优势越明显;更不需要多线程的锁机制(GIL)。
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。
协程的优点:
(1)无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能(但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力)
(2)无需原子操作锁定及同步的开销
(3)方便切换控制流,简化编程模型
(4)高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
协程的缺点:
(1)无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
(2)进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
def consumer(name): print("我要吃包子") while True: baozi=yield print("%s eating %s 包子"%(name,baozi)) def producer(name): c1.__next__() c2.__next__() n=0 while True: print(" 33[32;1m[producer] 33[0m is making baozi %s and %s" % (n, n + 1)) c1.send(n) c2.send(n+1) n+=2 if __name__ == '__main__': c1=consumer("alex") c2=consumer("tom") p1=producer("cookie")
import greenlet def test1(): print(12) g2.switch() print(34) g2.switch() print(96) def test2(): print(56) g1.switch() print(78) g1=greenlet.greenlet(test1)#创建一个协程对象 g2=greenlet.greenlet(test2) g1.switch()#启动协程/切换协程
gevnet是协程之间的自动切换
import gevent def func1(): print(12) gevent.sleep(2) print(56) def func2(): print(34) gevent.sleep(1) print(78) t1=gevent.spawn(func1)#创建一个线程对象 t2=gevent.spawn(func2) print(t1) gevent.joinall([t1,t2])#添加线程对象,并运行线程