计算机将任务平均的分配给不同的运算空间,可以提高运算速度,达到“多人同时处理任务” 的效果
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的运行
当然,也会出现不锁的时候是乱打印的情况,但是锁住的时候肯定是一个进程运行完之后,再运行另一个进程,锁住的过程不会有其他进程来捣乱
但是锁住之后,时间确实就变成了两倍,变成了串行的两个进程