热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python并发编程–多进程

在本章中,我们将更多地关注多处理和多线程之间的比较。多进程在一台计算机系统中使用两个或多个CPU单元。通过利用计算机系统中可用的全

在本章中,我们将更多地关注多处理和多线程之间的比较。

多进程

在一台计算机系统中使用两个或多个CPU单元。 通过利用计算机系统中可用的全部CPU核心,这是最好的方法来充分利用我们的硬件。

多线程

这是CPU通过同时执行多个线程来管理操作系统使用的能力。 多线程的主要思想是通过将进程分成多个线程来实现并行性。

下表显示了它们之间的一些重要区别 -









































编号多进程多程序
1多处理是指多个CPU同时处理多个进程。多程序同时在主存储器中保存多个程序,并使用单个CPU同时执行它们。
2它利用多个CPU。它利用单个CPU
3它允许并行处理。上下文切换。
4处理工作的时间更少。处理工作需要花费更多的时间。
5它有助于计算机系统设备的高效利用。效率低于多重处理。
6系统通常更昂贵。这样的系统更便宜。


消除全局解释器锁定(GIL)的影响

在使用并发应用程序时,Python中存在一个名为GIL(全局解释器锁)的限制。 GIL从来不允许我们利用CPU的多个内核,因此可以说Python中没有真正的线程。 GIL是互斥锁 - 互斥锁,它使线程安全。 换句话说,可以说GIL阻止了多个线程并行执行Python代码。锁一次只能由一个线程保存,如果想执行一个线程,那么它必须先获取锁。

通过使用多处理,可以通过GIL有效地绕过 -


  • 通过使用多处理,利用多个进程的能力,因此使用GIL的多个实例。

  • 由于这个原因,在程序中一次执行一个线程的字节码没有限制。



在Python中启动进程

可以使用以下三种方法在多处理模块内用Python启动进程 -


  • Fork

  • Spawn

  • Forkserver

使用Fork创建一个流程
Fork命令是在UNIX中找到的标准命令。 它用于创建称为子进程的新进程。 此子进程与称为父进程的进程同时运行。 这些子进程也与其父进程相同,并继承父进程可用的所有资源。 使用Fork创建流程时使用以下系统调用 -



  • fork() - 这是一个通常在内核中实现的系统调用,它用于创建进程的副本。


  • getpid() - 该系统调用返回调用进程的进程ID(PID)。

示例
以下Python脚本示例将演示如何创建新的子进程并获取子进程和父进程的PID -

import os
def child():
n = os.fork()
if n > 0:
print("PID of Parent process is : ", os.getpid())
else:
print("PID of Child process is : ", os.getpid())
child()

执行上面示例代码,得到以下结果 -

PID of Parent process is : 25989
PID of Child process is : 25990


用Spawn创建一个进程

Spawn意味着开始新的事物。 因此,产生一个过程意味着父过程创建一个新进程。 父进程异步继续执行或等待子进程结束其执行。 按照这些步骤产生一个进程 -


  • 导入多处理模块。

  • 创建对象进程。

  • 通过调用start()方法来启动进程活动。

  • 等待进程完成其工作并通过调用join()方法退出。

示例

以下Python脚本示例产生三个进程 -

import multiprocessing
def spawn_process(i):
print ('This is process: %s' %i)
return
if __name__ == '__main__':
Process_jobs = []
for i in range(3):
p = multiprocessing.Process(target = spawn_process, args = (i,))
Process_jobs.append(p)
p.start()
p.join()

执行上面示例代码,得到以下结果 -

This is process: 0
This is process: 1
This is process: 2


使用Forkserver创建一个进程

Forkserver机制仅适用于那些支持通过Unix Pipes传递文件描述符的所选UNIX平台。 考虑以下几点来理解Forkserver机制的工作 -


  • 服务器通过使用Forkserver机制来启动新进程。

  • 然后服务器接收命令并处理创建新进程的所有请求。

  • 要创建一个新的进程,python程序会向Forkserver发送一个请求,之后它会创建一个进程。

  • 最后,我们可以在程序中使用这个新创建的进程。



守护进程如何在Python中进行处理

Python多处理模块允许通过它的守护进程选项来守护进程。 守护进程或在后台运行的进程遵循与守护进程线程类似的概念。 要在后台执行该进程,需要将守护进程标志设置为true。 只要主进程正在执行,守护进程将继续运行,并在完成执行或主程序被终止后终止进程。

示例

在这里,我们使用与守护进程线程中使用的相同的示例。 唯一的区别是模块从多线程更改为多处理,并将守护标志设置为true。 但是,如下所示,输出结果会发生变化 -

import multiprocessing
import time
def nondaemonProcess():
print("starting my Process")
time.sleep(8)
print("ending my Process")
def daemonProcess():
while True:
print("Hello")
time.sleep(2)
if __name__ == '__main__':
nOndaemonProcess= multiprocessing.Process(target = nondaemonProcess)
daemOnProcess= multiprocessing.Process(target = daemonProcess)
daemonProcess.daemon = True
nondaemonProcess.daemon = False
daemonProcess.start()
nondaemonProcess.start()

执行上面示例代码,得到以下结果 -

starting my Process
ending my Process

输出与守护进程线程生成的输出相比是不同的,因为没有守护进程模式的进程有输出。 因此,主程序结束后,守护进程会自动结束以避免运行进程的持久性。


在Python中终止进程

可以使用terminate()方法立即终止或终止一个进程。 在完成执行之前,我们将使用此方法来终止在函数的帮助下创建的子进程。

例子

import multiprocessing
import time
def Child_process():
print ('Starting function')
time.sleep(5)
print ('Finished function')
P = multiprocessing.Process(target = Child_process)
P.start()
print("My Process has terminated, terminating main thread")
print("Terminating Child Process")
P.terminate()
print("Child Process successfully terminated")

输出结果 -

My Process has terminated, terminating main thread
Terminating Child Process
Child Process successfully terminated

该输出显示程序在执行使用Child_process()函数创建的子进程之前终止。 这意味着子进程已成功终止。


在Python中识别当前进程

操作系统中的每个进程都具有称为PID的进程标识。 在Python中,可以借助以下命令找出当前进程的PID -

import multiprocessing
print(multiprocessing.current_process().pid)

例子
以下Python脚本示例用于找出主进程的PID以及子进程的PID -

import multiprocessing
import time
def Child_process():
print("PID of Child Process is: {}".format(multiprocessing.current_process().pid))
print("PID of Main process is: {}".format(multiprocessing.current_process().pid))
P = multiprocessing.Process(target=Child_process)
P.start()
P.join()

执行上面示例代码,得到以下结果 -

PID of Main process is: 9401
PID of Child Process is: 9402


在子类中使用进程

可以通过对threading.Thread类进行子分类来创建线程。 另外,还可以通过对multiprocessing.Process类进行子分类来创建流程。 要在子类中使用流程,需要考虑以下几点 -


  • 需要定义一个Process类的新子类。

  • 需要覆盖_init_(self [,args])类。

  • 需要重写run(self [,args])方法来实现Process

  • 需要通过调用start()方法来启动进程。

参考以下代码 -

import multiprocessing
class MyProcess(multiprocessing.Process):
def run(self):
print ('called run method in process: %s' %self.name)
return
if __name__ == '__main__':
jobs = []
for i in range(5):
P = MyProcess()
jobs.append(P)
P.start()
P.join()

执行上面示例代码,得到以下代码-

called run method in process: MyProcess-1
called run method in process: MyProcess-2
called run method in process: MyProcess-3
called run method in process: MyProcess-4
called run method in process: MyProcess-5


Python多处理模块 - Pool类

如果在Python应用程序中讨论简单的并行处理任务,那么多处理模块提供了Pool类。 下面的Pool类方法可以用来在主程序中创建多个子进程。

apply()方法
该方法与ThreadPoolExecutorsubmit()方法类似,直到结果准备就绪。

apply_async()方法
当需要并行执行任务时,需要使用apply_async()方法将任务提交给池。 这是一个异步操作,直到执行完所有的子进程之后才会锁定主线程。

map()方法
就像apply()方法一样,它也会阻塞直到结果准备就绪。 它相当于内置的map()函数,它将多个块中的可迭代数据分开并作为单独的任务提交给进程池。

map_async()方法
它是map()方法的一个变体,apply_async()apply()方法的变体。 它返回一个结果对象。 当结果准备就绪时,就会应用一个可调用对象。 可调用函数必须立即完成; 否则,处理结果的线程将被阻止。

例子

以下示例实现执行并行执行的进程池。 通过multiprocessing.Pool方法应用square()函数,可以简单计算数字的平方。 然后使用pool.map()提交5,因为输入是从04的整数列表。结果将被存储在p_outputs中并被打印输出结果 -

def square(n):
result = n*n
return result
if __name__ == '__main__':
inputs = list(range(5))
p = multiprocessing.Pool(processes = 4)
p_outputs = pool.map(function_square, inputs)
p.close()
p.join()
print ('Pool :', p_outputs)

执行上面示例代码,得到以下结果 -

Pool : [0, 1, 4, 9, 16]


推荐阅读
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • MySQL索引详解与优化
    本文深入探讨了MySQL中的索引机制,包括索引的基本概念、优势与劣势、分类及其实现原理,并详细介绍了索引的使用场景和优化技巧。通过具体示例,帮助读者更好地理解和应用索引以提升数据库性能。 ... [详细]
  • 使用Numpy实现无外部库依赖的双线性插值图像缩放
    本文介绍如何仅使用Numpy库,通过双线性插值方法实现图像的高效缩放,避免了对OpenCV等图像处理库的依赖。文中详细解释了算法原理,并提供了完整的代码示例。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 掌握远程执行Linux脚本和命令的技巧
    本文将详细介绍如何利用Python的Paramiko库实现远程执行Linux脚本和命令,帮助读者快速掌握这一实用技能。通过具体的示例和详尽的解释,让初学者也能轻松上手。 ... [详细]
  • ImmutableX Poised to Pioneer Web3 Gaming Revolution
    ImmutableX is set to spearhead the evolution of Web3 gaming, with its innovative technologies and strategic partnerships driving significant advancements in the industry. ... [详细]
  • 本文介绍如何使用Python进行文本处理,包括分词和生成词云图。通过整合多个文本文件、去除停用词并生成词云图,展示文本数据的可视化分析方法。 ... [详细]
author-avatar
黄梓恒_
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有