示例代码如下:
# coding:utf-8import osimport timeimport multiprocessingdef work(count): # 定义一个 work 函数,打印输出 每次执行的次数 与 该次数的进程号 print('/'work/' 函数 第 {} 次执行,进程号为 {}'.format(count, os.getpid())) time.sleep(3) return '/'work/' 函数 result 返回值为:{}, 进程ID为:{}'.format(count, os.getpid())if __name__ == '__main__': pool = multiprocessing.Pool(3) # 定义进程池的进程数量,同一时间每次执行最多3个进程 results = [] for i in range(21): result = pool.apply_async(func=work, args=(i,)) # 传入的参数是元组,因为我们只有一个 i 参数,所以我们要写成 args=(i,) results.append(result) for result in results: print(result.get()) # 可以通过这个方式返回 apply_async 的返回值, # 通过这种方式也不再需要 使用 close()、join() 函数就可以正常执行。 # time.sleep(15) # 这里的休眠时间是必须要加上的,否则我们的进程池还未运行,主进程就已经运行结束,对应的进程池也会关闭。 # pool.close() # pool.join()
运行结果如下:
从运行结果可以看出,首先 work()
函数被线程池的线程执行了一遍,当第一组任务执行完毕紧接着执行第二次线程池任务的时候,打印输出了 apply_async
的返回值,证明返回值被成功的返回了。然后继续下一组的任务…
这些都是主要依赖于 异步
,关于 异步
的更多知识会在 异步
的章节进行详细的介绍。
进程锁
进程锁的概念
锁:大家都知道,我们可以给一个大门上锁。
结合这个场景来举一个例子:比如现在有多个进程同时冲向一个 "大门"
,当前门内是没有 “人”的(其实就是进程),锁也没有锁上。当有一个进程进去之后并且把 “门” 锁上了,这时候门外的那些进程是进不来的。在门内的 “人” ,可以在 “门” 内做任何事情且不会被干扰。当它出来之后,会解开门锁。这时候又有一个 “人” 进去了门内,并且重复这样的操作,这就是 进程锁
。它可以让锁后面的工作只能被一个任务来处理,只有它解锁之后下一个任务才会进入,这就是 “锁” 的概念。
而 进程锁
就是仅针对于 进程
有效的锁,当进程的任务开始之后,就会被上一把 “锁”;与之对应的是 线程锁
,它们的原理几乎是一样的。
进程锁的加锁与解锁
进程锁的使用方法:
通过 multiprocessing 导入 Manager 类
from multiprocessing import Manager
然后实例化 Manager
manager = Manager()
再然后通过实例化后的 manager 调用 它的 Lock() 函数
lock = manager.Lock()
接下来,就需要操作这个 lock 对象的函数
函数名 介绍 参数 返回值 acquire 上锁 无 无 release 解锁(开锁) 无 无
代码示例如下:
# coding:utf-8import osimport timeimport multiprocessingdef work(count, lock): # 定义一个 work 函数,打印输出 每次执行的次数 与 该次数的进程号,增加线程锁。 lock.acquire() # 上锁 print('/'work/' 函数 第 {} 次执行,进程号为 {}'.format(count, os.getpid())) time.sleep(3) lock.release() # 解锁 return '/'work/' 函数 result 返回值为:{}, 进程ID为:{}'.format(count, os.getpid())if __name__ == '__main__': pool = multiprocessing.Pool(3) # 定义进程池的进程数量,同一时间每次执行最多3个进程 manager = multiprocessing.Manager() lock = manager.Lock() results = [] for i in range(21): result = pool.apply_async(func=work, args=(i, lock)) # 传入的参数是元组,因为我们只有一个 i 参数,所以我们要写成 args=(i,) # results.append(result) # time.sleep(15) # 这里的休眠时间是必须要加上的,否则我们的进程池还未运行,主进程就已经运行结束,对应的进程池也会关闭。 pool.close() pool.join()
执行结果如下:
从上图中,可以看到每一次只有一个任务会被执行。由于每一个进程会被阻塞 3秒钟,所以我们的进程执行的非常慢。这是因为每一个进程进入到 work() 函数中,都会执行 上锁、阻塞3秒、解锁
的过程,这样就完成了一个进程的工作。下一个进程任务开始,重复这个过程… 这就是 进程锁的概念
。
其实进程锁还有很多种方法,在 multiprocessing
中有一个直接使用的锁,就是 “from multiprocessing import Lock。这个
Lock的锁使用和我们刚刚介绍的
Manager` 的锁的使用有所区别。(这里不做详细介绍,感兴趣的话可以自行拓展一下。)
锁
的使用可以让我们对某个任务 在同一时间只能对一个进程进行开发,但是 锁也不可以乱用
。因为如果某些原因造成 锁没有正常解开
,就会造成死锁
的现象,这样就无法再进行操作了。
因为 锁如果解不开
,后面的任务也就没有办法继续执行任务,所以使用锁一定要谨慎。
推荐学习:python视频教程