python 进程池与队列结合_python基础(进程的锁机制,进程队列,进程数据共享,进程池与回调函数)...

一、 进程锁(Lock):

1.1 定义:

1. 同一时刻同一段代码,只能有一个进程来执行这段代码

2. 锁的应用场景,当多个进程需要操作同一个文件/数据库的时候 ,

3. 会产生数据不安全,我们应该使用锁来避免多个进程同时修改一个文件

1.2 示例:

#示例:

importjsonimporttimefrom multiprocessing importProcess, Lock#查询余票

defsearch_ticket(name):

with open('ticket', encoding='utf-8') as f:

dic=json.load(f)print('%s查询余票为%s' % (name, dic['count']))#购买车票

defbuy_ticket(name):

with open('ticket', encoding='utf-8') as f:

dic=json.load(f)

time.sleep(2)if dic['count'] >= 1:print('%s买到票了' %name)

dic['count'] -= 1time.sleep(2)

with open('ticket', mode='w', encoding='utf-8') as f:

json.dump(dic, f)else:print('余票为0,%s没买到票' %name)#使用线程锁方式一:

defuse1(name, lock):

search_ticket(name)print('%s在等待' %name)

lock.acquire()print('%s开始执行了' %name)

buy_ticket(name)

lock.release()#使用线程锁方式二:

defuse2(name, lock):"""# with lock:

# 代码块

# 上下文管理:在__enter__方法中获取锁(acquire),在__exit__方法中释放锁(release)"""search_ticket(name)print('%s在等待' %name)

with lock:print('%s开始执行了' %name)

buy_ticket(name)if __name__ == '__main__':

lock=Lock()

l= ['alex', 'wusir', 'baoyuan', 'taibai']for name inl:

Process(target=use1, args=(name, lock)).start() #方式一

Process(target=use2, args=(name, lock)).start() #方式二

View Code

二、进程程队列(Queue):

2.1 定义:

多个进程之间的数据是隔离的

进程之间的数据交互可以通过网络/文件来实现的(socket)

2.2 进程通信的实现方式:

通过python的模块实现的:

基于原生socket

基于进程队列的

第三方的软件/工具来实现 : 基于网络的:

memcache redis rabbitMQ kafka - 软件名

IPC(进程之间的通信) - inter process communication

进程:Queuefrom multiprocessing importQueue

可以完成进程之间通信的特殊的队列

队列:Queuefrom queue importQueue

不能完成进程之间的通信,普通的队列

进程队列与普通队列

2.3 进程队列示例:

#队列(queue)示例:

from multiprocessing importQueue, Processdefson(q):print('-->', q.get()) #获取队列里面的值

if __name__ == '__main__':

q=Queue()

Process(target=son, args=(q,)).start() #创建一个子进程

q.put('wahaha') #入队

View Code

三、 生产者与消费者模型:

3.1 定义:

1. 调节生产者的个数或者消费者的个数来让程序的效率达到最平衡和最大化

2. 解耦思想

示例:

#生产者与消费者示例:

importtimeimportrandomfrom multiprocessing importProcess, Queue#生产者

defproducer(q):for i in range(10):

time.sleep(random.random())

food= 'Spam %s' %iprint('%s生产了%s' % ('Jane', food))

q.put(food)#消费者

defconsumer(q, name):whileTrue:

food= q.get() #food = 食物/None

if not food: break #当消费者消费完成后,最后拿到None时,退出消费者程序

time.sleep(random.uniform(1, 2))print('%s 吃了 %s' %(name, food))if __name__ == '__main__':

q=Queue()

p1= Process(target=producer, args=(q,)) #生产者

p1.start()

c1= Process(target=consumer, args=(q, 'Lisa')) #消费者

c1.start()

c2= Process(target=consumer, args=(q, 'Annie')) #消费者

c2.start()

p1.join()

q.put(None)#生产者完成生产后,队列最后加入None,表示已经生产完成

q.put(None) #每个消费者需要None退出程序

View Code

3.2  共享进程队列(消费者与生产者):

定义:

1.生产者生产完数据之后,一直阻塞等待消费者完成消费消费者队列为空时(task_done())返回一个消息给阻塞等待的生产者(join()), 生产者接收消息自动结束当前进程

2.把消费者设置为主进程的守护进程,当主进程的代码块结束后,守护进程(消费者)进程结束

示例:

#共享进程队列示例:

importtimeimportrandomfrom multiprocessing importJoinableQueue, Process#消费者

defconsumer(jq, name):whileTrue:

food=jq.get()

time.sleep(random.uniform(1, 2)) #模拟消费时间

print('%s吃完%s' %(name, food))

jq.task_done()#消费完成时(队列为空),返回一个消费完成的信息给到生产者

#生产者

defproducer(jq):for i in range(10):

time.sleep(random.random())

food= 'Spam%s' %iprint('%s生产了%s' % ('Jane', food))

jq.put(food)

jq.join()#接收到消费者队列为空,阻塞的生产者程序结束

if __name__ == '__main__':

jq= JoinableQueue(5)

c1= Process(target=consumer, args=(jq, 'Annie')) #消费者

p1 = Process(target=producer, args=(jq,)) #生产者

c1.daemon = True #设置消费者为守护进程

c1.start()

p1.start()

p1.join()#等待生产者进程结束,标志主进程代码块结束

View Code

四、 进程之间的数据的数据共享(Manager类):

多次开启进程,管理进程,销毁进程会拖慢进程的执行速度

Manager类可以实现数据共享,当Manager类中对列表/字典操作(+= -= /= *=)的情况数据不安全,需要进行加锁保证数据安全

示例:

#数据共享:

from multiprocessing importProcess, Manager, Lockdeffunc(dic, lock):

lock.acquire()#加锁

dic['count'] -= 1 #子进程的数据修改

lock.release() #释放锁

if __name__ == '__main__':

lock=Lock()

m= Manager() #实例化一个Manager类

dic = m.dict({'count': 100}) #通过对象创建一个字典

p_l =[]for i in range(100):

p= Process(target=func, args=(dic, lock))

p.start()

p_l.append(p)for p in p_l: p.join() #阻塞等待子程序结束

print(dic)

View Code

五、 进程池(concurrent.futures类)

5.1 为什么需要创建进程池:

1.不能有多少个任务就开多少个进程,这样开销太大了

2.用有限的进程执行无限的任务,多个被开启的进程重复利用,节省的是开启\销毁\多个进程切换的时间

5.2 进程池的创建:

#方式一(for循环):

importosfrom concurrent.futures importProcessPoolExecutordefmake(i):print('%s 制作螺丝%s' %(os.getpid(), i))return i ** 2

if __name__ == '__main__':

p= ProcessPoolExecutor(4) #创建一个进程池

for i in range(100):

p.submit(make, i)#向进程池中提交任务

p.shutdown() #阻塞 直到池中的任务都完成为止

print('所有的螺丝都制作完了')

for循环方式

#方式二(map实现):

importosfrom concurrent.futures importProcessPoolExecutordefmake(i):print('%s 制作螺丝%s' %(os.getpid(), i))return i ** 2

if __name__ == '__main__':

p= ProcessPoolExecutor(4) #创建一个进程池

p.map(make, range(100)) #submit的简便用法

p.shutdown() #阻塞

print('所有的螺丝都制作完了')

map方式

5.3 进程池的对象的返回值:

#进程池的返回值:

importosimporttimefrom concurrent.futures importProcessPoolExecutordefmake(i):

time.sleep(0.2)print('%s 制作螺丝%s' %(os.getpid(), i))return i ** 2

if __name__ == '__main__':

ret_l=[]

p= ProcessPoolExecutor(4) #创建一个进程池

#方式一:

for i in range(100):

ret=p.submit(make, i)

ret_l.append(ret)for r inret_l:print(r.result()) #返回每个子线程的返回值

#方式二

ret = p.map(make, range(100)) #返回一个生成器对象

print(ret) #

for i in ret: #每次获取到一个返回值

print(i)

View Code

六、 进程池与回调函数:

#回调函数:

#示例:

importtimeimportrandomfrom concurrent.futures importProcessPoolExecutor#子进程

deffunc1(n):

time.sleep(random.random())#生成一个0-1之间的随机小数

print('in func1 %s' %n)return n * 2

#回调函数

defcall_back(arg):print(arg) # 结果对象

print(arg.result()) #结果值,例如:4,6,10...

if __name__ == '__main__':

p= ProcessPoolExecutor(4) #创建一个进程池

#方式一:

for i in range(10): #提交10个任务

ret = p.submit(func1, i) # #print(ret) # 返回一个结果对象

ret.add_done_callback(call_back) #函数回调call_back

#方式二:

ret_l =[]for i in range(10):

ret= p.submit(func1, i) #返回结果对象

ret_l.append(ret)for r inret_l:

call_back(r)#循环回调

回调函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值