并发与并行
并发和并行是两个非常容易混淆的概念。他们都可以表示两个或多个任务一起执行,但是偏重点有点不同。并发偏重于多个任务交替执行,而多个任务之间有可能还是串行的。并发是逻辑上的同时发生,而并行是物理上的同时发生,然而并行的偏重点在于同时执行。
并发:指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进行同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。这就能好比一个人一把铁锹同时挖三个坑,每个坑都挖一下然后去挖下一个,虽然三个坑都变大,但实际上同一时间只有一个坑在被挖。
严格意义上来说,并行的多个任务是真实的同时执行,而对于并发来说,这个过程只是交替的,一会运行任务一,一会运行任务二,系统会不停的在两者间切换,对于外部观察者来说,即使多个任务是串行并发的,也会造成多个任务并行执行的错觉。
并行,指在同一时刻,有多条指令在多个处理器上同时执行,就好像三个人三把铁锹同时在挖三个坑,三个坑一起变大,所以无论从微视还是宏观来看,二者都是一起执行的。
线程与进程
开个qq,开了一个进程;开个迅雷,开了一个进程
在qq的这个进程里,传输文字开一个线程。在这个软件运行的过程(在这个进程里),多个工作同时运转,完成了qq的运行,那么这“多个工作”分别有一个线程,所以一个进程管着多个线程,一个进程有且至少有一个线程
- 多进程不共享全局变量
from multiprocessing import Process
import time
a = 100
def work1():
for i in range(10):
global a
print('这个是任务1-----{}'.format(a))
a += 1
time.sleep(0.5)
def work2():
for i in range(10):
global a
print('这个是任务2----{}'.format(a))
a+=1
time.sleep(0.5)
#多进程执行多任务
#创建两个进程
p1 = Process(target=work1)
p2 = Process(target=work2)
p1.start()
p2.start()
p1.join()
p2.join()
- 解决多进程之间通信问题
import time
# from queue import Queue
#queue.Queue是进程内非阻塞队列
#multipprocess.Queue是跨进程通信队列
#多进程前者是各自私有,后者是各子进程共有
#process之间有时需要通信,操作系统提供了很多机制来实现进程间的通信
#创建一个队列添加10个任务
from multiprocessing import Process,Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
for value in ['A', 'B', 'C']:
print('Put %s to queue...' % (value))
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
while True:
if not q.empty():
value = q.get(True)
print('Get %s from queue.' % (value))
time.sleep(random.random())
else:
break
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 等待pw结束:
pw.join()
# 启动子进程pr,读取:
pr.start()
pr.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
print('所有数据都写入并且读完')
进程池参数介绍
- apply_async:使用非阻塞的方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的
关键字参数列表 - close:关闭Pool,使其不在接受新的任务
- terminate:不管任务是否完成,立即终止
- join:主进程阻塞,等待子线程的退出,必须在close或terminate之后使用;
进程池的使用
from multiprocessing import Pool,Manager
import os
a = 0
def read1(q):
q.get()
a = 0
for i in range(100000):
a = a + 1
print(a)
print('Get %s from queue.' % (os.getpid()))
# time.sleep(random.random())
if __name__ == '__main__':
q = Manager().Queue()
pool = Pool(10)
for value in range(100):
q.put(value)
for i in range(100):
if not q.empty():
# print('haha')
pool.apply_async(func=read1,args=(q,))
else:
break
pool.close()
pool.join()
- 1000个I/O任务分别使用3个进程和3个线程来完成,哪个更快
#进程快
#做多任务的时候进程快,只用进程不合理,进程占用资源大,应进程里面开线程,线程里面开协程
import os
import queue
import time
from multiprocessing import Manager,Pool
from threading import Thread
#线程的队列(只能在一个进程中使用)
import requests
# requests.get('http://www.apple.com/')
#如果是mac电脑需要打开此行注释方可运行,否则在进行网络请求的时候会卡住。
X = 0
def work(q3):
while not q3.empty():
url = q3.get()
print('xxx')
requests.get(url= url)
print('ooo')
global X
X += 1
print(X)
print('该进程运行了%s次'%(X))
if __name__ == '__main__':
q3 = Manager().Queue()
for i in range(1000):
q3.put('https://www.apple.com/')
pool = Pool(3)
st = time.time()
for i in range(3):
pool.apply_async(work,args=(q3,))
#关闭进程池,停止往进程池中添加新的任务
pool.close()
#主进程等待,子进程结束在进行
pool.join()
et = time.time()
print('耗时{}',format(et-st))
# #耗时{} 30.68186616897583
# def main():
# q = queue.Queue()
# for i in range(1000):
# q.put('https://www.apple.com/')
# st = time.time()
# t1 = Thread(target=work,args=(q,))
# t2 = Thread(target=work,args=(q,))
# t3 = Thread(target=work,args=(q,))
# t1.start()
# t2.start()
# t3.start()
# t1.join()
# t2.join()
# t3.join()
# et = time.time()
# print('耗时',et-st)
# if __name__ == '__main__':
# main()
# 线程 耗时 35.74414277076721
- 1000个计算密集型任务线程、进程之间的比较
很明显计算密集型任务,因为GIL锁的存在python线程并不占优势
import time
from multiprocessing import Manager,Pool
import requests
X = 0
def work(q3):
while not q3.empty():
q3.get()
a = 0
for i in range(100000):
a = a + i
print(a)
global X
X += 1
print('该进程运行了%s次'%(X))
if __name__ == '__main__':
q3 = Manager().Queue()
for i in range(10000):
q3.put(i)
pool = Pool(3)
st = time.time()
for i in range(3):
pool.apply_async(work,args=(q3,))
#关闭进程池,停止往进程池中添加新的任务
pool.close()
#主进程等待,子进程结束在进行
pool.join()
et = time.time()
print('耗时{}',format(et-st))
# 耗时{} 19.595630168914795
import time
from threading import Thread
from queue import Queue
X = 0
def work(q):
while not q.empty():
q.get()
a = 0
for i in range(100000):
a = a + i
print(a)
global X
X += 1
if __name__ == '__main__':
q = Queue()
for i in range(10000):
q.put(i)
t1 = Thread(target=work,args=(q,))
t2 = Thread(target=work,args=(q,))
t3 = Thread(target=work,args=(q,))
st = time.time()
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
et = time.time()
print('线程执行时间%s'%(et-st))
#线程执行时间55.236459732055664
进程在进行计算密集型任务时体现出了极大的优势,并且进程是可以完成并行的,但是进程占用的资源也是极大的,使用的时候要考虑资源消耗。
网友评论