本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于进程池与进程锁的相关问题,包括进程池的创建模块,进程池函数等等内容,下面一起来看一下,希望对大家有帮助。
|
本篇文章给大家带来了关于python的相关知识,其中主要介绍了关于进程池与进程锁的相关问题,包括进程池的创建模块,进程池函数等等内容,下面一起来看一下,希望对大家有帮助。
推荐学习:python视频教程 进程池什么是进程池上一章节关于进程的问题我们提到过,进程创建太多的情况下就会对资源消耗过大。为了避免出现这种情况,我们就需要固定进程的数量,这时候就需要进程池的帮助。 我们可以认为进程池就是一个池子,在这个池子里提前创建好一定数量的进程。见下图:
比如这个红色矩形阵列就代表一个进程池子,在这个池子中有6个进程。这6个进程会伴随进程池一起被创建,不仅如此,我们在学习面向对象的生命周期的时候曾经说过,每个实例化对象在使用完成之后都会被内存管家回收。 我们的进程也会伴随着创建与关闭的过程而被内存管家回收,每一个都是如此,创建于关闭进程的过程也会消耗一定的性能。而进程池中的进程当被创建之后就不会被关闭,可以一直被重复使用,从而避免了创建于关闭的资源消耗,也避免了创建于关闭的反复操作提高了效率。 当然,当我们执行完程序进程池关闭的时候,进程也随之关闭。 当我们有任务需要被执行的时候,会判断当前的进程池当中有没有空闲的进程(所谓空闲的进程其实就是进程池中没有执行任务的进程)。有进程处于空闲状态的情况下,任务会找到进程执行该任务。如果当前进程池中的进程都处于非空闲状态,则任务就会进入等待状态,直到进程池中有进程处于空闲状态才会进出进程池从而执行该任务。 这就是进程池的作用。 进程池的创建模块 - multiprocessing创建进程池函数 - Pool
进程池的常用方法当创建了进程池对象之后,我们要对它进程操作,让我们来看一下都有哪些常用方法(函数)。
apply_async 函数演示案例接下里我们在 Pycharm 中创建一个脚本,练习一下关于进程池的使用方法。
示例代码如下: # coding:utf-8import osimport timeimport multiprocessingdef work(count):
# 定义一个 work 函数,打印输出 每次执行的次数 与 该次数的进程号
print('\'work\' 函数 第 {} 次执行,进程号为 {}'.format(count, os.getpid()))
time.sleep(3)
# print('********')if __name__ == '__main__':
pool = multiprocessing.Pool(3)
# 定义进程池的进程数量,同一时间每次执行最多3个进程
for i in range(21):
pool.apply_async(func=work, args=(i,))
# 传入的参数是元组,因为我们只有一个 i 参数,所以我们要写成 args=(i,)
time.sleep(15)
# 这里的休眠时间是必须要加上的,否则我们的进程池还未运行,主进程就已经运行结束,对应的进程池也会关闭。运行结果如下:
从上图中我们可以看到每一次都是一次性运行三个进程,每一个进程的进程号是不一样的,但仔细看会发现存在相同的进程号,这说明进程池的进程号在被重复利用。这证明我们上文介绍的内容,进程池中的进程不会被关闭,可以反复使用。 而且我们还可以看到每隔3秒都会执行3个进程,原因是我们的进程池中只有3个进程;虽然我们的 同样的,进程号在顺序上回出现一定的区别,原因是因为我们使用的是一种
close 函数与 join 函数 演示在上文的脚本中, 我们使用 如果没有 示例代码如下: # coding:utf-8import osimport timeimport multiprocessingdef work(count):
# 定义一个 work 函数,打印输出 每次执行的次数 与 该次数的进程号
print('\'work\' 函数 第 {} 次执行,进程号为 {}'.format(count, os.getpid()))
time.sleep(3)
# print('********')if __name__ == '__main__':
pool = multiprocessing.Pool(3) # 定义进程池的进程数量,同一时间每次执行最多3个进程
for i in range(21):
pool.apply_async(func=work, args=(i,))
# 传入的参数是元组,因为我们只有一个 i 参数,所以我们要写成 args=(i,)
# time.sleep(15)
pool.close()
pool.join()运行结果如下:
从上面的动图我们可以看出, PS:如果我们的主进程会一直执行,不会退出。那么我们并不需要添加 在后面学习 WEB 开发之后,不退出主进程进行工作是家常便饭。还有一些需要长期执行的任务也不会关闭,但要是只有一次性执行的脚本,就需要添加
示例代码如下: # 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()运行结果如下:
从运行结果可以看出,首先 这些都是主要依赖于 进程锁进程锁的概念锁:大家都知道,我们可以给一个大门上锁。 结合这个场景来举一个例子:比如现在有多个进程同时冲向一个 而 进程锁的加锁与解锁进程锁的使用方法:
代码示例如下: # 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() 函数中,都会执行 其实进程锁还有很多种方法,在
因为 推荐学习:python视频教程 以上就是详细了解Python进程池与进程锁的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |
