day9-进程池的使用

概述

之前不是说,多个进程间的内存都是独立的。在进程里面怎么也有锁的概念,为什么?虽然进程间都是独立运行的,但是他们共享同一块屏幕,所以为了避免打印出的数据不乱(加锁的情况下进程独占屏幕),所以加锁。

进程同步

用法:使用multiprocess模块中的Lock锁模块实现进程锁

#-*- coding:utf-8 -*-
from multiprocessing import Process, Lock


def f(l, i):
    l.acquire() #获取锁
    print('hello world', i)
    l.release() #释放锁


if __name__ == '__main__':
    lock = Lock() #生成锁的实例

    for num in range(10): #启动10个进程
        p = Process(target=f, args=(lock, num)) #将锁对象作为参数传给子进程f
        p.start() #启动子进程

#运行输出

hello world 0
hello world 2
hello world 1
hello world 3
hello world 4
hello world 5
hello world 6
hello world 7
hello world 8
hello world 9

Process finished with exit code 0

进程池

作用:在使用Python处理并发任务时,最简单的模式就是主进程等待任务,当有新任务来到时,启动一个新的进程来处理当前任务。这种每个任务一个进程的处理方式,每处理一个任务都伴随着一个进程的创建,运行和销毁,如果进程的运行时间越短,创建和销毁的时间所占比重就越大,显然,我们应该尽量避免创建和销毁进程本身的额外开销,提高进程的运行效率。我们可以使用进程池来减少进程的创建和开销,提高进程对象的复用。

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用的进程为止。

进程池的两个方法

1.apply

功能:同步执行也就是串行执行

from  multiprocessing import Process, Pool #导入模块
import time,os


def Foo(i):
    time.sleep(2)
    print("in process:",os.getpid())
    return i + 100


def Bar(arg):
    print('-->exec done:', arg)


pool = Pool(5)  #允许进程池里同时放入5个进程

for i in range(10): #启动10个进程
    pool.apply(func=Foo, args=(i,)) #串行

print('end')
pool.close()
pool.join()  # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭(不等进程执行完毕)。

#运行输出
in process: 32048
in process: 32049
in process: 32050
in process: 32051
in process: 32052
in process: 32048
in process: 32049
in process: 32050
in process: 32051
in process: 32052
end

Process finished with exit code 0

解析:串行执行的只有进程池中的5个,其他5个进程被挂起了。当进程池中进程执行结束一个,另外5个进程就进去一个,如此反复执行。直到全部执行结束。

2.apply_async

功能:异步执行也就是并发执行

from  multiprocessing import Process, Pool
import time,os


def Foo(i):
    time.sleep(2)
    print("in process:",os.getpid())
    return i + 100


def Bar(arg):
    print('-->exec done:', arg)


pool = Pool(5)  #允许进程池里同时放入5个进程

for i in range(10): #启动10个进程
    pool.apply_async(func=Foo, args=(i,)) #并行

print('end')
pool.close()
pool.join()  # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭(不等进程执行完毕)。

#运行输出

end
in process: 32114
in process: 32116
in process: 32117
in process: 32115
in process: 32118
in process: 32114
in process: 32116
in process: 32117
in process: 32115
in process: 32118

Process finished with exit code 0

解析:并行执行的只有进程池中的5个,其他5个进程被挂起了,等待5个同时执行结束,再放入进程池中另外5个,再同时执行。join()函数是等待所有进程池中的进程执行完毕后再关闭程序。没写的话,就是说不等进程执行结束与否,直接关闭程序。

在以上进程的并发方法中存在一个callback参数,它的作用可以实现回调,下面修改下例子

from  multiprocessing import Process, Pool
import time,os


def Foo(i):
    time.sleep(2)
    print("in process:",os.getpid())
    return i + 100


def Bar(arg):
    print('-->exec done:%s 回调函数Bar的PID:%s'%(arg,os.getpid()))


pool = Pool(5)  #允许进程池里同时放入5个进程
print("主进程的PID:",os.getpid())
for i in range(10): #启动10个进程
    pool.apply_async(func=Foo, args=(i,),callback=Bar) #callback=回调

print('end')
pool.close()
pool.join()  # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭(不等进程执行完毕)。

#输出
主进程的PID: 32163
end
in process: 32166
in process: 32165
in process: 32164
in process: 32168
in process: 32167
-->exec done:101 回调函数Bar的PID:32163
-->exec done:102 回调函数Bar的PID:32163
-->exec done:100 回调函数Bar的PID:32163
-->exec done:104 回调函数Bar的PID:32163
-->exec done:103 回调函数Bar的PID:32163
in process: 32165
-->exec done:105 回调函数Bar的PID:32163
in process: 32166
in process: 32164
in process: 32168
-->exec done:106 回调函数Bar的PID:32163
-->exec done:107 回调函数Bar的PID:32163
-->exec done:108 回调函数Bar的PID:32163
in process: 32167
-->exec done:109 回调函数Bar的PID:32163

Process finished with exit code 0

解析:可以看出每个子进程执行结束后都执行了Bar()函数,通过结果可以发现并不是子进程调用了Bar()函数,而是主进程执行了回调Bar()函数。

应用场景

启动10个进程到备份服务器上备份数据,备份完后要写一条日志到数据库。那么就可以使用回调函数实现单个进程(主进程)连接数据库,而不是10个子进程或更多的子进程,每次都调用Bar()函数启动10个或更多的进程同时连接到数据库,这样就节约了资源,提高了运行效率。

 

posted @ 2017-12-11 23:46  Mr.hu  阅读(119)  评论(0编辑  收藏  举报