入门python多进程(二)

关于python多进程的创建方式请先看入门python多进程(一)

3.进程锁:

由于进程之间的数据不共享,有时候多个进程需要同时访问同一个文件,这就会引发数据安全或顺序混乱问题

这种情况下,可以使用进程锁,加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行的修改。这种方式会减慢速度,但是牺牲了速度而保证了数据安全。

举一个最常见的买票问题。ticket.json里写的{“count”: 4},表示现在只有4张票,我会启动5个进程去买票,这就意味着第5个进程会买票失败

import os
import time
import json
import random  
import multiprocessing
from multiprocessing import Lock

def buy_ticket(file_name, lock):
	#进程锁开启,同一时刻只允许一个进程买票操作
    lock.acquire()
    with open(file_name, 'r', encoding='utf-8') as f:
        dic = json.loads(f.read())
    if dic["count"] > 0:
        print("{}查询,还剩{}张票" .format(os.getpid(),dic["count"]))
        dic["count"] -= 1
        time.sleep(random.randint(1,3))
        with open(file_name, 'w', encoding='utf-8') as f:
            f.write(json.dumps(dic))
        print("{}购票成功".format(os.getpid()))
    else:
        print("{}购票失败" .format (os.getpid()))
    #记得进程锁释放
    lock.release()

if __name__ == "__main__":
    lock = Lock()
    for i in range(5):
        sub_process = multiprocessing.Process(target=buy_ticket, args=("ticket.json", lock) )
        sub_process.start()

运行结果:
在这里插入图片描述

4.进程池:

对于操作对象数目不大的时候,可以直接利用multiprocessing中的Process动态成生多个进程。但是当被操作对象数目很大的时候,开启很大数量的进程反而会降低效率。因此,这时候可以使用进程池去管理一定数量的进程,避免太过繁琐的手动去限制进程数量,此时可以发挥进程池的功效。

Pool可以提供指定数量的进程供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。

A.阻塞(同步)方式

import os 
import time
from multiprocessing import Pool

def work(n):
    print("{} statrt".format(os.getpid()))
    time.sleep(1)
    print("{} end".format(os.getpid()))
    return n * 2

if __name__ == "__main__":
    pool = Pool(processes=3) #定义线程个数
    res_l = []
    for i in range(6):
        res = pool.apply(work, (i, ))#apply是阻塞方式
        res_l.append(res)#直接获得结果
    pool.close()#关闭pool,使其不在接受新的任务
    pool.join()#主进程阻塞,子进程结束,主进程才可以结束
    
    print(res_l)

运行结果:可以看出9个任务,重复使用3个进程进行处理。此外,阻塞的方式是某个进程跑完之后,下一个进程才会开启。

2648 statrt
2648 end
17160 statrt
17160 end
9616 statrt
9616 end
2648 statrt
2648 end
17160 statrt
17160 end
9616 statrt
9616 end
[0, 2, 4, 6, 8, 10]

B.非阻塞(异步)方式

import os 
import time
from multiprocessing import Pool

def work(n):
    print("{} statrt".format(os.getpid()))
    time.sleep(1)
    print("{} end".format(os.getpid()))
    return n * 2

if __name__ == "__main__":
    pool = Pool(processes=3) #定义线程个数
    res_l = []
    for i in range(6):
        res = pool.apply_async(work, (i, ))#非阻塞方式
        res_l.append(res)#非直接获得结果
    pool.close()#关闭pool,使其不在接受新的任务
    pool.join()#主进程阻塞,子进程结束,主进程才可以结束
    
    print([res.get()for res in res_l])#get方式获取结果

运行结果:可以看出进程是异步进行的,此外,进程的结果不可以直接获得,而是要通过.get()方法获得

10292 statrt
8292 statrt
14144 statrt
10292 end
10292 statrt
8292 end
14144 end
8292 statrt
14144 statrt
10292 end
8292 end
14144 end
[0, 2, 4, 6, 8, 10]

猜你喜欢

转载自blog.csdn.net/weixin_42096202/article/details/109557853