• 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的步骤,然后有一个就是最后的输出顺序是按照参数的顺序来的,而不是执行完成的顺序。

    暂停一下。未完待续

  • 相关阅读:
    HTML CSS整理笔记
    2020软件工程最后一次作业
    form表单的基本用法
    图片预加载和懒加载(2)——懒加载
    ES6——promise基础
    图片预加载和懒加载(2)——预加载
    图片预加载和懒加载(1)
    js时间——转换为我们需要的格式
    原生js瀑布流
    富文本——小程序中使用特殊符号及标签
  • 原文地址:https://www.cnblogs.com/slose-notes/p/9676608.html
Copyright © 2020-2023  润新知