多进程

多进程:在多个CPU运行
多进程实现方式:函数式,继承式
multiprocessing模块:
multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数)
multiprocessing模块的功能众多:支持子进程、通信和共享数据、
执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。
需要再次强调的一点是:与线程不同,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内。
Process类的
创建进程的类
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,
表示一个子进程中的任务(尚未启动)

#函数式
import  multiprocessing,time
def run(name):
    time.sleep(5)
    print("来了",name)
if __name__ == '__main__':
    p1 = multiprocessing.Process(target=run,kwargs={"name":"老弟1"},name="l1")
    p2 = multiprocessing.Process(target=run,kwargs={"name":"老弟2"},name="l2")
    p3 = multiprocessing.Process(target=run,kwargs={"name":"老弟3"},name="l3")
    p1.daemon = True
    #print(p1.name)#进程名称
    p1.start()
    p2.start()
    p3.start()
    #p1.terminate()#强制终止进程

    #print(p1.is_alive())
    #time.sleep(6)
    #print(p1.is_alive())

    #p1.join(timeout=2)
    #print("主线程结束")

    p1.terminate()#关闭进程,不立刻关
    print(p1.is_alive())
    time.sleep(1)
    print(p1.is_alive())
#继承式
import  multiprocessing,time
class MyProcess(multiprocessing):
    def __init__(self):
        multiprocessing.Process.__init__(self)
    def run(self):
        print("来了老弟")
if __name__=="__main__":
    p1 = MyProcess()
    p2 = MyProcess()
    p1.start()
    p2.start()

全局解释器锁GIL

GIL导致线程不能利用多核优势
解决方案可以根据任务的类型来处理,如果是I/O密集型,则需要开多线程提高效率,
如果是计算密集型则需要多进程

锁(进程同步)

import multiprocessing,time
#lock = multiprocessing.Lock()
def work(name,lock):
    lock.acquire()
    with open("a.txt",mode="r+",encoding="utf8") as f:
        c = int(f.read())
        c -= 1
        time.sleep(1)
        print(name,c)
        f.write(str(c))
    lock.release()

if __name__ == '__main__':
    lock = multiprocessing.Lock()
    p1 = multiprocessing.Process(target=work,args=("p1",))
    p2 = multiprocessing.Process(target=work,args=("p2",))
    p3 = multiprocessing.Process(target=work,args=("p3",))
    p1.start()
    p2.start()
    p3.start()

进程间通信(IPC)

方式一:队列(推荐使用)

import multiprocessing,time

def work(q):
    if not q.empty():
        print(q.get())

if __name__=="__main__":
    q = multiprocessing.Queue(maxsize=3)
    q.put(1)
    q.put(2)
    q.put(3)
    # q.get()
    # print(q.get())
    p1 = multiprocessing.Process(target=work,args=(q,))
    p2 = multiprocessing.Process(target=work, args=(q,))
    p1.start()
    p2.start()

方式二:管道

import multiprocessing
def jieshou(left,right):#左接收,右发送
    #right.close()
    while True:
        print(left.recv())
        left.send("你好")
def fasong(left,right):
    #left.close()
    while True:
        right.send("我是被发送出去的数据")
        print(right.recv())

if __name__=='__main__':
    left,right = multiprocessing.Pipe()
    p1 = multiprocessing.Process(target=jieshou,args=(left,right))
    p2 = multiprocessing.Process(target=fasong, args=(left, right))
    p1.start()
    p2.start()

进程池

开多进程的目的是为了并发,如果有多核,通常有几个核就开几个进程,进程开启过多,效率反而会下降
当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。
在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。
创建进程池的类:
Pool([numprocess [,initializer [, initargs]]]):创建进程池
参数介绍:
numprocess:要创建的进程数,如果省略,将默认使用cpu_count()的值
initializer:是每个工作进程启动时要执行的可调用对象,默认为None
initargs:是要传给initializer的参数组