进程 线程 异步编程 websockets梳理
一 进程,多进程,进程池
进程:一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元
一个进程至少一个线程才能运行,一条生产电视的流水线就是一个进程,每个工人就是线程。
一个进程中可以并发多个线程,每条线程并行执行不同的任务。
进程在执行过程中拥有独立的内存单元,而多个线程共享内存
1 import time 2 import os 3 from multiprocessing import Process 4 5 def long_time_task(i): 6 print(os.getpid()) 7 time.sleep(i) 8 print("结果:{}".format(8**20)) 9 10 if __name__ == '__main__': 11 print("当前木进程:{}".format(os.getpid())) 12 start = time.time() 13 p1 = Process(target=long_time_task,args=(1,)) 14 p2 = Process(target=long_time_task,args=(2,)) 15 print("等待所有子进程执行完成") 16 p1.start() 17 p2.start() 18 p1.join() #为了让母进程阻塞,等待子进程完成在打印时间 19 p2.join() 20 end = time.time() 21 print("用事{}秒".format(end-start))
创建子进程的几种方式
apply()
:同步阻塞执行,上一个子进程结束后才能进行下一个子进程(不推荐) apply(func, args=(), kwds={}, callback=None, error_callback=None)apply_async()
:异步非阻塞执行,每个子进程都是异步执行的(并行)(推荐) apply(func, args=(), kwds={}, callback=None, error_callback=None)map()
:同步阻塞 若子进程有返回值,且需集中处理,建议采用此种方式map_async()
:异步非阻塞,若想统一处理结果,map_async
比apply_async
更方便imap()
:内存不够用可以采用此种方式,速度慢于map()
imap_unordered
:imap()
的无序版本(不会按照调用顺序返回,而是按照结束顺序返回),返回迭代器实例
1 from multiprocessing import Pool, cpu_count 2 import os 3 import time 4 5 6 def long_time_task(i): 7 print('子进程: {} - 任务{}'.format(os.getpid(), i)) 8 time.sleep(2) 9 print("结果: {}".format(8 ** 20)) 10 11 12 if __name__=='__main__': 13 print("CPU内核数:{}".format(cpu_count())) 14 print('当前母进程: {}'.format(os.getpid())) 15 start = time.time() 16 p = Pool(8) 17 #for i in range(15): 18 # p.apply_async(long_time_task, args=(i,)) 19 p.map(long_time_task,range(5)) #第二个参数是个迭代器 20 print('等待所有子进程完成。') 21 p.close() 22 p.join() #join之前要close 23 end = time.time() 24 print("总共用时{}秒".format((end - start)))
1 # coding=utf-8 2 3 import multiprocessing 4 import time 5 6 7 def run(a): 8 return a * a 9 10 11 data = [] 12 13 14 def my_callback(result): 15 data.append(result) 16 17 18 if __name__ == '__main__': 19 st = time.time() 20 pool = multiprocessing.Pool(6) 21 22 # 总耗时:0.4497215747833252 23 future = pool.map_async(run, range(20000)) 24 print(future.get()) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 25 26 # # 总耗时:3.019148111343384 27 # for i in range(20000): 28 # pool.apply_async(run, args=(i,), callback=my_callback) 29 # 30 # print(data) 31 32 pool.close() 33 pool.join() 34 print(f"总耗时:{time.time() - st}")
多进程向同一文件写入数据
1 def callback(result): 2 """回调函数""" 3 with open('a.txt', 'a+', encoding="utf-8") as f: 4 f.write(str(result) + "\n") 5 6 7 def run(num): 8 return num * num 9 10 11 if __name__ == '__main__': 12 pool = multiprocessing.Pool(6) 13 for i in range(1000): 14 pool.apply_async(run, args=(i, ), callback=callback) 15 #pool.map_async(run, range(1000), callback=callback) 16 pool.close() 17 pool.join()
二 线程,多线程,线程池
线程:是操作系统能够进行运算调度的最小单位,被包含在进程中,
对CPU密集型代码(比如循环计算) - 多进程效率更高
对IO密集型代码(比如文件操作,网络爬虫) - 多线程效率更高。
1 import threading 2 import time 3 4 5 def long_time_task(i): 6 print('当前子线程: {} 任务{}'.format(threading.current_thread().name, i)) 7 time.sleep(2) 8 print("结果: {}".format(8 ** 20)) 9 10 11 if __name__=='__main__': 12 start = time.time() 13 print('这是主线程:{}'.format(threading.current_thread().name)) 14 thread_list = [] 15 for i in range(1, 3): 16 t = threading.Thread(target=long_time_task, args=(i, )) 17 thread_list.append(t) 18 19 for t in thread_list: 20 t.start() 21 22 for t in thread_list: 23 t.join() 24 25 end = time.time() 26 print("总共用时{}秒".format((end - start)))
t.setDaemon(True) #主进程结束不再执行子进程
1 #!/usr/bin/env python 2 import time 3 import os 4 import threading 5 from multiprocessing.pool import ThreadPool 6 7 def long_time_task(i): 8 print(os.getpid()) 9 time.sleep(i) 10 print("结果:{}".format(8**20)) 11 12 if __name__ == '__main__': 13 start = time.time() 14 pool = ThreadPool(5) 15 pool.map(long_time_task,range(9)) 16 pool.close() 17 pool.join() 18 end = time.time() 19 print(f"总用时:{end-start}")
三 concurrent.futures
该方法是3.2后引入的新模块
ThreadPoolExecutor
:多线程编程ProcessPoolExecutor
:多进程编程,适合计算密集型任务Executor
:执行器,用于管理工作池Future
:管理工作计算出的结果
1 import time 2 import requests 3 from concurrent.futures import ThreadPoolExecutor, as_completed, ProcessPoolExecutor 4 def fetch(url): 5 r = requests.get(url) 6 return r.json()['args']['a'] 7 8 9 if __name__ == '__main__': 10 start = time.time() 11 numbers = range(12) 12 url = 'http://httpbin.org/get?a={}' 13 # with ThreadPoolExecutor(max_workers=3) as executor: 14 # task_list = [executor.submit(fetch, url.format(n)) for n in range(12)] 15 # for future in as_completed(task_list): 16 # print(future.result()) 17 #map()方式 18 with ThreadPoolExecutor(max_workers=3) as executor: 19 future = executor.map(fetch, (url.format(n) for n in numbers)) 20 for result in future: 21 print(result) 22 print("total_time:", time.time() - start)
1 import numbers 2 import time 3 import requests 4 from concurrent.futures import ThreadPoolExecutor, as_completed, ProcessPoolExecutor 5 6 7 def fib(n): 8 if n < 2: 9 return 1 10 return fib(n - 1) + fib(n - 2) 11 12 13 def call_back(future): 14 """ 15 回调(可获得返回值和错误) 16 """ 17 worker_execption = future.exception() 18 if worker_execption: 19 print("异常:", worker_execption) 20 print(future.result()) 21 22 23 def test(n): 24 if n % 2 == 0: 25 n / 0 #发生异常 26 return n * 2 27 28 29 if __name__ == '__main__': 30 numbers = range(20) 31 start = time.time() 32 with ProcessPoolExecutor(max_workers=3) as executor: 33 # work_dict = {executor.submit(fib, i): i for i in numbers} #字典{future:i} 34 # print(work_dict) 35 # for future in as_completed(work_dict): 36 # num = work_dict[future] 37 # try: 38 # data = future.result() 39 # except Exception as e: 40 # print(e) 41 # else: 42 # print(f"fib({num}={data})") 43 #map方式 44 # for num, result in zip(numbers, executor.map(fib, numbers)): 45 # print(f"fib({num}={result})") 46 #通过add_done_callback获取结果和错误异常 47 for i in numbers: 48 executor.submit(test, i).add_done_callback(call_back) 49 print(f"total_time:{time.time()-start}")
以上测试 都是map稍快一些,也更简洁。
四 协程异步IO(asyncio)
协程:又称微线程,是一种比线程更加轻量级的存在,最重要的是,协程不被操作系统内核管理,协程是完全由程序控制的(函数直间互相调用切换)。
对于多核CPU,利用多进程+协程的方式,能充分利用CPU,获得极高的性能。
如同一个进程可以有很多线程一样,一个线程可以有很多协程。
异步是继多线程、多进程之后第三种实现并发的方式,主要用于IO密集型任务的运行效率提升,
协程概念是从 3.4 版本增加的,但 3.4 版本采用是生成器实现,为了将协程和生成器的使用场景进行区分,使语义更加明确,在 python 3.5 中增加了 async
和 await
关键字,用于定义原生协程。
python 中的 asyncio 库提供了管理事件、协程、任务和线程的方法,以及编写并发代码的原语,即 async
和 await
。
异步IO的asyncio库使用事件循环驱动的协程实现并发。用户可主动控制程序,在认为耗时IO处添加await(yield from)。在asyncio库中,协程使用@asyncio.coroutine装饰,使用yield from来驱动,在python3.5中作了如下更改:
@asyncio.coroutine -> async
yield from -> await
async def:用于编写 协程函数;
await:等待 协程/任务 的执行完成
要真正运行一个协程,asyncio 提供了 3 种主要机制:
asyncio.run() 函数用来运行最高层级的入口点 main() 函数(参考上面示例);
await 等待一个协程(对象);
asyncio.create_task() 函数用来并发运行作为 asyncio 任务 的多个协程。
以上 3 种方式均可使 协程 被调度执行。
1 # coding=utf-8 2 3 import asyncio 4 from multiprocessing.connection import wait 5 6 async def coroutine_example(): 7 await asyncio.sleep(1) 8 print('ok') 9 return "ok" 10 11 12 coro = coroutine_example() 13 14 loop = asyncio.get_event_loop() 15 task = loop.create_task(coro) 16 print('运行情况:', task) 17 18 loop.run_until_complete(task) 19 print('再看下运行情况:', task.result()) 20 loop.close()
1 import asyncio 2 3 def my_callback(future): 4 print('返回值:', future.result()) 5 6 async def coroutine_example(): 7 await asyncio.sleep(1) 8 return 'ok' 9 10 coro = coroutine_example() 11 12 loop = asyncio.get_event_loop() 13 14 task = loop.create_task(coro) 15 task.add_done_callback(my_callback) 16 17 loop.run_until_complete(task) 18 loop.close()
1 async def coroutine_example(name): 2 print("doing_name:", name) 3 await asyncio.sleep(2) 4 print('done_name:', name) 5 return "wzy" 6 7 8 loop = asyncio.get_event_loop() 9 tasks = [ 10 loop.create_task(coroutine_example('wzy_' + str(i))) for i in range(3) 11 ] 12 wait_core = asyncio.wait(tasks) #控制多任务 13 loop.run_until_complete(wait_core) 14 for task in tasks: 15 print("wxh_result:", task.result()) 16 loop.close()
1 import asyncio 2 3 a = [] 4 5 def callback(future): 6 print("111111", future.result()) 7 a.append(future.result()) 8 9 10 async def coroutine_example(name): 11 print("doing_name:", name) 12 await asyncio.sleep(2) 13 print('done_name:', name) 14 return "wzy" 15 16 17 loop = asyncio.get_event_loop() 18 tasks = [] 19 for i in range(3): 20 task = loop.create_task(coroutine_example('Zarten_' + str(i))) 21 task.add_done_callback(callback) 22 tasks.append(task) 23 wait_coro = asyncio.wait(tasks) 24 loop.run_until_complete(wait_coro) 25 loop.close() 26 print("a:", a)
六 websockets
pass