多进程multiprocess学习

计算机将任务平均的分配给不同的运算空间,可以提高运算速度,达到“多人同时处理任务” 的效果

1 创建multiprocess
创建process和thread如出一辙:

#进程和线程的import差不多
import multiprocessing as mp
import threading as td


def job(a,b):
    print('aaaaa')
    
#创建多进程的方法也和多线程差不多,job都是不加括号,加了括号代表调用函数,不加括号代表索引  
t1 = td.Thread(target = job,args = (1,2))
p1 = mp.Process(target = job,args = (1,2))

t1.start()
p1.start()

t1.join()
p1.join()

在IDLE和spyder的IDE直接运行会没有任何反应,需要到terminal中运行,转到py文件所在路径之后:python process.py就可以运行print的结果了

2 queue进程输出

import multiprocessing as mp

def job1(q):#multiprocess所做的job也是不能有return的值的
    result = 0
    for i in range(100):
        result = result + i
    print(result)
    q.put(result) #把运行出来的result放进q里面
    
def job2(q):
    result = 0
    for i in range(100):
        result = result + i**2
    print(result)
    q.put(result)

if __name__ == '__main__': #多进程一定要在这个main框架下运行不然会报错
    q = mp.Queue()
    #args如果只有一个值,也要写逗号,表示一个元组,用来表示参数的索引
    p1 = mp.Process(target = job1,args = (q,))   
    p2 = mp.Process(target = job2,args = (q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

这里分两次put进q里面,那么从q里面get的时候也可以get两次,第一次get第一次的结果,第二次get第二次的结果,第三次再想get 的时候就会出错:
在这里插入图片描述

import multiprocessing as mp

def job1(q):#multiprocess所做的job也是不能有return的值的
    result = 0
    for i in range(100):
        result = result + i
    q.put(result) #把运行出来的result放进q里面
    
def job2(q):
    result = 0
    for i in range(100):
        result = result + i**2
    print(result)
    q.put(result)

if __name__ == '__main__': #多进程一定要在这个main框架下运行不然会报错
    q = mp.Queue()
    #args如果只有一个值,也要写逗号,表示一个元组,用来表示参数的索引
    p1 = mp.Process(target = job1,args = (q,))   
    p2 = mp.Process(target = job2,args = (q,))
    
    p1.start()
    p2.start()
    
    
    p1.join()#等p1进行之后再进行后面的操作
    p2.join()#等p2进行之后再进行后面的操作
    #但是p1和p2的顺序不根据代码顺序,同时运行
    
    #哪个先得到结果,哪个就打印出来
    res1 = q.get()
    print(res1)
    res2 = q.get()
    print(res2)
    print(res1 + res2)

所以会出现两种结果:
在这里插入图片描述
在这里插入图片描述

3 效率问题

import multiprocessing as mp
import threading as td
import time

num = 600000

def job1(q):#multiprocess所做的job也是不能有return的值的
    result = 0
    for i in range(num):
        result = result + i
    q.put(result) #把运行出来的result放进q里面
    
def job2(q):
    result = 0
    for i in range(num):
        result = result + i**2
    q.put(result)
    
def job3(q):
    result = 0
    for i in range(num):
        result = result + i**3
    q.put(result)


#这是一个双进程,分别完成一部分任务,再合起来的效果   
def multicore():
    q1 = mp.Queue()
    #args如果只有一个值,也要写逗号,表示一个元组,用来表示参数的索引
    p1 = mp.Process(target = job1,args = (q1,))   
    p2 = mp.Process(target = job2,args = (q1,))
    p3 = mp.Process(target = job3,args = (q1,))
    
    p1.start()
    p2.start()
    p3.start()
    
    
    p1.join()#等p1进行之后再进行后面的操作
    p2.join()#等p2进行之后再进行后面的操作
    p3.join()
    #但是p1和p2的顺序不根据代码顺序,同时运行
    
    #哪个先得到结果,哪个就打印出来
    res1 = q1.get()
    res2 = q1.get()
    res3 = q1.get()
    print('multicore result: ',res1 + res2 + res3)

#这是一个单进程,一个人完成两部分计算任务的效果    
def normal():
    res = 0
    for i in range(num):
        res = res + i
    for i in range(num):
        res = res + i**2
    for i in range(num):
        res = res + i**3
    print('normal result: ',res)
    
#这是一个多线程,多个线程,执行一个计算任务
def multithread():
    q2 = mp.Queue() #多进程中的q放进多线程中也是可以的
    #args如果只有一个值,也要写逗号,表示一个元组,用来表示参数的索引
    t1 = td.Thread(target = job1,args = (q2,))   
    t2 = td.Thread(target = job2,args = (q2,))
    t3 = td.Thread(target = job3,args = (q2,))
    
    t1.start()
    t2.start()
    t3.start()
    
    
    t1.join()#等p1进行之后再进行后面的操作
    t2.join()#等p2进行之后再进行后面的操作
    t3.join()
    #但是p1和p2的顺序不根据代码顺序,同时运行
    
    #哪个先得到结果,哪个就打印出来
    res1 = q2.get()
    res2 = q2.get()
    res3 = q2.get()
    print('multithread result: ',res1 + res2 + res3)
    
if __name__ == '__main__':
    t = time.time() #记录此时的时间
    normal()
    t1 = time.time() #计算完normal的时间
    print('normal time:',t1-t)
    multithread() 
    t2 = time.time() #计算完multithread的时间
    print('multithread time:',t2-t1)
    multicore()
    t3 = time.time() #计算multicore的时间
    print('multicore time:',t3-t2)

在这里插入图片描述
可以看到多线程似乎还没有单线程的速度快,而多进程就比较快了,并且这个差距随着运算量变大越来越明显,比方说num再增大num = 10000000
在这里插入图片描述
在这里插入图片描述
但是当运算量较小时,多进程就起不到什么效果,甚至还没有但进程快:num = 1000

在这里插入图片描述

4 进程池pool
进程池有两种用法:map和apply_async

map:
把所有的要运行的东西放入进程池里面,python会帮你分配进程

import multiprocessing as mp

def job(x):
    return x*x
#如果用mp.Process,job就不能有返回值,只能用进程队列取出来运行结果
#如果有进程池了,那么就可以有返回值

def multicore():
    #1 定义一个pool
    pool = mp.Pool()
    #2 往pool里面放入你的方程和要运算的值,等待自动分配进程和核
    res = pool.map(job,range(100000000))
    #3 返回得到的结果
    print(res)
    
if __name__ == '__main__':
    multicore()

可以看到八个核每个核都满载运转
在这里插入图片描述
修改mp.Pool()的参数可以指定占用多少个核,但是我指定了之后,IDE就闪退了…

apply_async:

import multiprocessing as mp

def job(x):
    return x*x
#如果用mp.Process,job就不能有返回值,只能用进程队列取出来运行结果
#如果有进程池了,那么就可以有返回值

def multicore():
    '''
    map相当于是自己一次性把任务自动分给多个进程做运算
    '''
    #1 定义一个pool
    pool = mp.Pool(processes = 8) #用到八个核
    #2 往pool里面放入你的方程和要运算的值,等待自动分配进程和核
    res = pool.map(job,range(10))
    #3 返回得到的结果
    print(res)
    
    '''
    apply_async相当于是一次运算一个值,分给一个进程算
    '''
    res = pool.apply_async(job,(2,)) #传入一个值被一个核运算
    #如果要传入多个值,会报错
    print(res.get()) #从res里面拿出来结果
    
    #如果要传入很多个值,每次用一个进程做运算,要用到迭代器
    multi_res = [pool.apply_async(job,(i,)) for i in range(10)]
    print([res.get() for res in multi_res])#再一个一个从列表中拿出来
    
if __name__ == '__main__':
    multicore()

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

5 共享内存
多线程共享变量,直接用global就可以了,但是在多进程里面,进程之间变量的交流存在于不同cpu之间,global是行不通的,只能用shared memory

import multiprocessing as mp
#共享内存的变量设置
value = mp.Value('d',1)#定义一个double型的1
array = mp.Array('i',[1,2,3,4])#定义一个不同于numpy的列表,不能是多维的,只能是一维的

6 Lock
现在随便写一段多进程处理同一个任务的代码,看它们之间是怎么竞争完成这些任务的计算的

import multiprocessing as mp
import time

def job(v,num,q):#做一个循环的操作    
    for _ in range(10):
        time.sleep(0.1)
        v.value += num  #共享内存的摄取值形式一定要是**.value
        q.put(v.value)

def multicore():
    q = mp.Queue()
    v = mp.Value('i',0) #定义一个共享内存的变量v
    p1 = mp.Process(target = job,args = (v,1,q))
    p2 = mp.Process(target = job,args = (v,3,q))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    
    res = 0
    for _ in range(20):
        res = q.get()
        print(res)



if __name__ == '__main__':
    multicore()  

在这里插入图片描述
这样打印出来的东西很乱
因为两个进程在抢夺这个共享内存的值,有的时候就会出现重叠
如果想要两个进程分开进行,就要添加lock锁

import multiprocessing as mp
import time

def job(v,num,q):#做一个循环的操作    
    for _ in range(10):
        time.sleep(0.1)
        v.value += num  #共享内存的摄取值形式一定要是**.value
        q.put(v.value)

def multicore():
    q = mp.Queue()
    v = mp.Value('i',0) #定义一个共享内存的变量v
    p1 = mp.Process(target = job,args = (v,1,q))
    p2 = mp.Process(target = job,args = (v,3,q))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    
    res = 0
    for _ in range(20):
        res_pre = res
        res = q.get()
        if (res-res_pre) == 1:
            print('p1 is working...:',res)
        elif(res-res_pre) == 3:
            print('p2 is working...',res)
        else:
            print('...')
        
    print('multicore end')

def job2(v,num,q,l):#做一个循环的操作   
    l.acquire()
    for _ in range(10):
        time.sleep(0.1)
        v.value += num  #共享内存的摄取值形式一定要是**.value
        q.put(v.value)
    l.release()

def multicore_lock():
    l = mp.Lock()
    q2 = mp.Queue()
    v2 = mp.Value('i',0) #定义一个共享内存的变量v
    p1 = mp.Process(target = job2,args = (v2,1,q2,l))
    p2 = mp.Process(target = job2,args = (v2,3,q2,l))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    
    res = 0
    for _ in range(20):
        res_pre = res
        res = q2.get()
#        print(res)
        if (res-res_pre) == 1:
            print('p1 is working...:',res)
        elif(res-res_pre) == 3:
            print('p2 is working...',res)
        else:
            print('...')
        
    
    print('multicore_lock end')


if __name__ == '__main__':
    t1 = time.time()
    multicore()   
    t2 = time.time()
    multicore_lock()
    t3 = time.time()
    print('multicore:',t2-t1)
    print('multicore_lock',t3-t1)

分别用不锁和锁的运行,看他们各自的运行情况和时间
p1 is working…: 1
p2 is working… 4
p1 is working…: 5
p2 is working… 8
p1 is working…: 9
p2 is working… 12
p1 is working…: 13
p2 is working… 16
p1 is working…: 17
p2 is working… 20
p1 is working…: 21
p2 is working… 24
p1 is working…: 25
p2 is working… 28
p1 is working…: 29
p2 is working… 32
p1 is working…: 33
p2 is working… 36
p1 is working…: 37
p2 is working… 40
multicore end
p1 is working…: 1
p1 is working…: 2
p1 is working…: 3
p1 is working…: 4
p1 is working…: 5
p1 is working…: 6
p1 is working…: 7
p1 is working…: 8
p1 is working…: 9
p1 is working…: 10
p2 is working… 13
p2 is working… 16
p2 is working… 19
p2 is working… 22
p2 is working… 25
p2 is working… 28
p2 is working… 31
p2 is working… 34
p2 is working… 37
p2 is working… 40
multicore_lock end
multicore: 1.2201902866363525
multicore_lock 3.403937339782715

进程锁保证了进程p1的完整运行,然后才进行了进程p2的运行

当然,也会出现不锁的时候是乱打印的情况,但是锁住的时候肯定是一个进程运行完之后,再运行另一个进程,锁住的过程不会有其他进程来捣乱
在这里插入图片描述

但是锁住之后,时间确实就变成了两倍,变成了串行的两个进程
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值