Python学习之路-随笔03 多线程/进程和协程(下篇)

下面属于协程的应用和之前剩下的没写详细的。

asyncio

上篇说过了协程之间切换的开销极小,用这个相对于threading的优势以及业务场景对比还有各种细分的对比能扯很多,我觉得在我目前的阶段不需要太纠结这个

即把这个当成threading的替代即可,asyncio可以简单认为比threading并发量更大,内存开销更小就行了(GIL日常先背个锅)

再说说简单的用法,首先asyncio是一个消息循环,有什么用呢?首先说一下协程工作完一段代码之后要返回主线程,但是这时候可能主线程也在忙,而asyncio相当于

一个信箱,FIFO样式的,协程工作完就把完成通知丢到“信箱”里面去,供主线程有空的时候顺序读取以便安排新的任务。

看代码:

 1 import threading
 2 import asyncio
 3 
 4 @asyncio.coroutine
 5 def t1():
 6     print('去洗菜', threading.currentThread())
 7     yield from asyncio.sleep(5)
 8     print('炒菜', threading.currentThread())
 9     
10 @asyncio.coroutine
11 def t2():
12     print('洗米', threading.currentThread())
13     yield from asyncio.sleep(5)
14     print('煮饭', threading.currentThread())
15 
16 @asyncio.coroutine
17 def t3():
18     print('洗衣服', threading.currentThread())
19     yield from asyncio.sleep(5)
20     print('晾衣服', threading.currentThread())
21     
22 loop = asyncio.get_event_loop()
23 tasks = [t1(),t2(),t3()]
24 loop.run_until_complete(asyncio.wait(tasks))
25 loop.close()
out:  去洗菜 <_MainThread(MainThread, started 7732)>
      洗米 <_MainThread(MainThread, started 7732)>
      洗衣服 <_MainThread(MainThread, started 7732)>
      炒菜 <_MainThread(MainThread, started 7732)>
      煮饭 <_MainThread(MainThread, started 7732)>
      晾衣服 <_MainThread(MainThread, started 7732)>

@asyncio.coroutine 表面这是一个要扔到消息循环(loop)的协程。asyncio.get_event_loop()是创建一个消息循环,然后分配任务,执行任务并等待任务结束,关闭消息循环。这就是一个简单的用法。

然后为了简化@asyncio.coroutine和yield from,从python3.5开始引入了async and await,使用方法就是用async替换掉@asyncio.coroutine,await替换掉yield from

async def t1():
    print('去洗菜', threading.currentThread())
    await asyncio.sleep(5)
    print('炒菜', threading.currentThread())

然后还有诸如绑定回调,协程嵌套等等其他用法暂时参考https://www.cnblogs.com/zhaof/p/8490045.html,不然就等我后面的更新哈哈哈哈哈哈<( ̄︶ ̄)↗ 

aiohttp

为什么写这玩意儿呢,我隐隐觉得以后会用到它,所以先记下来。

这玩意儿是基于asyncio(就是上面那玩意儿)实现的HTTP框架,可以实现单线程并发IO,主要用于服务器端。毕竟HTTP作为一个IO操作开销也是很大的呀

用之前就先得装好pip install aiohttp或者在ananconda里面点一点安装

真的只是先记下来啊,待我以后再来一篇(¬_¬)

concurrent.futures

一个类似于其他语言的线程池的概念,用的是multiprocessing,真正的并行计算。上面的协程只是伪并行计算。

首先要用到的东西concurrent.futures.Executor,里面有两个

ThreadPoolExecutor和ProcessPoolExecutor,建池子的时候要指定用哪个,然后给里面的max_workers这个参数安排一下数量,给几个核干活。

然后用submit提交任务和任务参数,submit(fn, args, kwargs),然后done执行,result获取结果。

 1 from concurrent.futures import ThreadPoolExecutor
 2 import time
 3 
 4 
 5 def task(msg):
 6     time.sleep(5)
 7     return msg
 8 
 9 
10 # 创建一个线程池
11 pool = ThreadPoolExecutor(max_workers=2)
12 
13 # 往线程池加入2个task
14 t1 = pool.submit(task, 'hello')
15 t2 = pool.submit(task, 'world')
16 
17 print(t1.done())
18 time.sleep(5)
19 print(t2.done())
20 
21 print(t1.result())
22 print(t2.result())
View Code

然后还有一个判断任务是否结束的问题,可以用as_completed这个方法来实现(用之前要导入= =)

for future in as_completed(all_task):
    data = future.result()

大概这样用

还有一个map函数,比如给同一个任务分配不同的参数丢进线程池执行

args = ['hello', 'world']
for data in pool.map(task, args):
    print(data)

这样用呢省去了submit的步骤,然后有一个就是最后的输出顺序是按照参数的顺序来的,而不是执行完成的顺序。

暂停一下。未完待续

posted @ 2018-09-19 19:42  小蜗_slose  阅读(111)  评论(0编辑  收藏  举报