Python多进程笔记(Python_MultiProcess)

第1点关于多进程的用法。首先我们来搞清楚, 到底什么叫做多进程呢?

在前面那个部分当中呢, 我们是采用了多线程的技术办法去分别处理那些不同的事情, 从表面上观察的话, 这样使用多线程来处理工作, 并不见得其效率就比使用单线程进行循环处理的效率会更高。而多进程则是主要利用了咱们电脑CPU所具备的多核特性这种方式, 目的是为了提高咱们在处理多项任务时候的整体效率表现。

b. 现在要开始着手, 去把一个进程给建立起来。

我们要去创建一个进程的话, 那我们就得先把那个跟这个进程有关的模块先拿来用一下, 然后给它取了一个叫作mp这个名字来代替。

那个进程, 它是拥有类似于线程的那种方法的。举个具体的例子来看, 如下面所示:

python 复制代码
import multiprocessing as mp

def job(a, b):

print(a + b)

if __name__ == '__main__':

p1 = mp.Process(target= job, args = (1, 2))

p1.start()

p1.join()

c. 在多进程这种环境里面, 关于那个叫做Queue的队列对象到底该拿去怎么用。

在上面提到的那种多线程的情境里, 大家会使用 Queue 这个物件来把工作的结果给存起来, 并且用在多个线程彼此之间进行沟通的场合。而在多进程的运行环境里, Queue 所发挥的作用仍然是负责保存那些工作产出, 以及用来实施不同进程间的信息交流这一类的事情。

让我们通过观察下面所提供的这个示例代码的具体情况, 以便弄明白如何运用 Queue 来进行数据的保存操作, 其具体的表现形式如下:

python 复制代码
import multiprocessing as mp

def job(q):

res = 0

for i in range(1000):

res += i + i ** 2 + i ** 3

q.put(res)

if __name__ == '__main__':

q = mp.Queue()

p1 = mp.Process(target= job, args = (q, )) #注意这里的args即使只有一个参数,也必须加上逗号,表示这个参数是一个可迭代的对象

p2 = mp.Process(target= job, args = (q, ))

p1.start()

p2.start()

p1.join()

p2.join()

res1 = q.get()

res2 = q.get()

print('Process1 compute result1: %d' % res1)

print('Process2 compute result2: %d' % res2)

d. 在一般情况下, 我们把多线程处理和多进程处理的效率进行比较, 同时也和正常处理方式下的效果做一个对照。

请看一下下面的这个情况, 咱们拿双核处理器来做个测试, 先去建立两个进程, 再去建立两个线程, 让那个单线程在里面跑两次循环, 去干相同的作业,把这三者的效率放在一起比较的话是可以发现, 多进程在计算方面是会比多线程和普通方法的效率高一些的, 可是因为有个叫GIL的东西存在着呢, 多线程看起来像是把作业分给了不同的线程去处理一样, 但是在数量级很大的操作面前, 它自己会在单核里面切换线程, 从而耗费掉不少的时间。

所以, 在大多数的情况之下, 多线程进行数据处理的那些效果, 它往往是比不上单线程去进行循环操作的。具体的例子, 如下面所示哈:

python 复制代码
import multiprocessing as mp

import threading as tp

import time

def job(q):

res = 0

for i in range(1000000):

res += i + i ** 2 + i ** 3

q.put(res)

def MultiProcessJob():

q = mp.Queue()

p1 = mp.Process(target= job, args = (q, )) #注意这里的args即使只有一个参数,也必须加上逗号,表示这个参数是一个可迭代的对象

p2 = mp.Process(target= job, args = (q, ))

p1.start()

p2.start()

p1.join()

p2.join()

res1 = q.get()

res2 = q.get()

print('Process1 compute result1: %d' % res1)

print('Process2 compute result2: %d' % res2)

def MultiThreadJob():

q = mp.Queue()

t1 = tp.Thread(target= job, args = (q, )) #注意这里的args即使只有一个参数,也必须加上逗号,表示这个参数是一个可迭代的对象

t2 = tp.Thread(target= job, args = (q, ))

t1.start()

t2.start()

t1.join()

t2.join()

res3 = q.get()

res4 = q.get()

print('Thread1 compute result3: %d' % res3)

print('Thread2 compute result4: %d' % res4)

def NormalJob():

res = 0

for i in range(2):

for j in range(1000000):

res += i + i ** 2 + i ** 3

print('Normal compute result5: %d' % res)

if __name__ == '__main__':

st = time.time()

NormalJob()

ft = time.time()

print('Normal Time is:', ft - st)

st1 = time.time()

MultiThreadJob()

ft1 = time.time()

print('MultiThread Time is', ft1 - st1)

st2 = time.time()

MultiProcessJob()

ft2 = time.time()

print('MultiProcess Time is', ft2 - st2)

'''

result:

Normal compute result5: 3000000

Normal Time is: 1.0905730724334717

Thread1 compute result3: 249999833333583333000000

Thread2 compute result4: 249999833333583333000000

MultiThread Time is 1.2889320850372314

Process1 compute result1: 249999833333583333000000

Process2 compute result2: 249999833333583333000000

MultiProcess Time is 0.668349027633667

'''

e. 当使用进程池这一对象的时候啊, 就叫做用Pool这个方法进行。

计算机中的 CPU 拥有多核资源, 进程池可以自动为我们将这些多核资源分配给计算任务。当我们想要使用多个进程去分别处理相同的工作时, 如果手动操作, 需要创建出四个或者更多的进程实例, 这个过程显得较为繁琐且麻烦。

因此为了解决这一难题, 引入了进程池的方式。通过进程池来创建进程并利用 CPU 的多核资源进行工作, 整体操作上会变得非常便捷和简单。

Pool类的作用是可以提供给用户一定数量的进程, 这些进程是供用户来调用的。如果当有新的请求被提交到Pool里面的时候, 因为池子还没有满额。

所以就会创建一个新的进程, 这个新创建的进程是用来执行对应的请求的。

但是如果池子已经满了之后, 提交的请求就需要先等着。要等到池子里面有旧进程结束了, 然后才会再创建新的进程来进行这些请求的处理工作。

参考下面代码

python 复制代码
import multiprocessing as mp

def job(x) :

return x * x

def multiProcess():

pool = mp.Pool(processes = 4) #利用4核处理

res = pool.map(job, range(100)) #将结果map组合起来

print(res)

res = pool.apply_async(job, (2, )) #apply_async方法是异步阻塞,不用等待当前进程执行完毕,随时根据系统调度来进行切换

print(res.get())

multi_res = [pool.apply_async(job, (i, )) for i in range(100)]

print([res.get() for res in multi_res])

if __name__ == '__main__':

multiProcess()

f. 共享内存这种情况, 还有进程锁这种东西, 这个锁就是。

所谓共享内存, 它的意思就是你的计算机处理器存在多个核心。假设我们的这个处理器是一个四核处理器的型号。那么我们在进行计算工作的时候, 会想要让系统先去完成对一个特定变量的运算过程。紧接着我们就想让在这个变量本身上面去继续执行其他操作任务。

基于这样的需求状况出现以后, 我们就是需要去使用这种叫做共享内存的技术手段来实现相关功能。使用.Value('i', int类型的数值)。之所以使用lock, 是为了保证各个进程之间能够单独执行完毕。这样做不会发生抢占式对共享内存中的数据进行修改的情况。例子如下:

python 复制代码
import multiprocessing as mp

import time

def job(v, num, lock):

lock.acquire()

for i in range(10):

time.sleep(0.2)

v.value += num

print(v.value)

lock.release()

def multiProcess():

lock = mp.Lock()

v = mp.Value('i', 0)

p1 = mp.Process(target=job, args=(v, 10, lock))

p2 = mp.Process(target=job, args=(v, 100, lock))

p1.start()

p2.start()

p1.join()

p2.join()

if __name__ == '__main__':

multiProcess()

这个 Code 的主要功能, 是给定了两个进程去对共享内存当中所存储的数据进行同一个操作。在这个过程里面, 一个是执行了add 10这一个动作, 另外一个是执行add 100这一个动作。通过采用lock锁这种方式来控制各个进程之间互不干扰。

Code欢迎给个star

相关推荐
进击的荆棘20 天前
Linux系统——进程间通信之system V
linux·共享内存·system v
MoRanzhi120321 天前
第6篇(中)· 使用 PyQt5 实现 2048 高性能计算版:无头后台求解与三档运行模式
python·pyqt·数据持久化·多进程·进程间通讯·后台任务·断点续跑
码上有光1 个月前
Linux进程通信——共享内存、消息队列和信号量
android·linux·运维·共享内存·通信
半仙白桑1 个月前
内核篇第十五讲:system-V共享内存
linux·共享内存·shmget·shmat·shmdt·shmctl
handler012 个月前
【Linux】线程与虚拟内存的底层世界
linux·运维·服务器·c++·线程·虚拟地址空间·共享内存
神威难绷泪2 个月前
Linux消息队列 & 共享内存 笔记
linux·消息队列·共享内存
祖力552 个月前
进程间通信(IPC机制):消息队列与共享内存
linux·消息队列·共享内存·通信·进程间通信
微小冷2 个月前
pyqt+matplotlib多进程图像刷新
pyqt·matplotlib·进程通信·多进程·queue·process
我不会插花弄玉3 个月前
9.进程间通信(上)【由浅入深-Linux】
linux·共享内存·进程通信