zoukankan      html  css  js  c++  java
  • 协程

    一、协程

    协程就是一个单线程完成并发并执行多个任务(用于提高效率,在检测到IO操作时,切换到其他的非IO操作,这样的话在操作系统中程序依然没有阻塞,可以尽可能多的占用CPU内存)

    在CPython中,如果任务是计算密集型,使用协程是无法提高效率的,反而会因为切换任务而导致效率降低,这种情况下只能使用进程

    IO密集型:多线程会比多进程效率高,因为线程的开销比进程小很多

    本质上协程还是只有一个进程,一旦遇到IO操作,整个线程的开销就卡主了

    协程仅在以下场景能够提高效率:

      1.任务是IO密集型

      2.一定要可以检测到IO操作,并且在IO即将阻塞时切换到计算任务,从而使得CPU尽可能多的执行你的线程

    二、同步异步

    同步:发起一个任务后,必须原地等待任务执行结束,拿到一个明确的结果

    异步:发起一个任务后,不需要等待,代码还可以继续向下执行

    异步任务的效率高于同步,比如当一个任务不需要立即获取结果,并且还有其他任务需要处理,那就发起异步任务

    发起一个任务的两种方式:多进程,多线程

    阻塞:程序遇到了IO操作,导致代码无法继续执行,交出了CPU的执行权

    非阻塞:没有遇到任何IO操作,即使遇到了IO操作,也不会阻塞代码执行

    同步和异步的区别:

      阻塞一个意味着CPU被切走了

      而异步有可能是因为计算任务比较耗时

    三、异步回调

    获取异步任务结果的方式

      爬虫:1.获取到HTML文档 2.从文档中取出需要的数据

    回调(回调函数):

      给异步绑定一个函数,当任务完成是会自动调用该函数

      优点:不需要原地等待,任务一结束就可以立即获取到

    异步回调之爬虫例子
     1 from concurrent.futures import ThreadPoolExecutor
     2 import requests
     3 import threading
     4 
     5 #生产
     6 def get_data(url):
     7     print("%s正在处理%s",threading.current_thread().name,url)
     8     resp = requests.get(url)
     9     print("%s获取完成"%url)
    10     # print(resp.text)
    11     return resp.text,url
    12 
    13 #消费
    14 def parser_data(f):
    15     res = f.result()
    16     print("解析长度:%s,地址:%s"%(len(res[0]),res[1]))
    17     print("当前线程:%s"% threading.current_thread().name)
    18 #要爬取的地址列表
    19 urls = ["https://www.baidu.com","https://www.bilibili.com","https://www.csdn.net"]
    20 pool = ThreadPoolExecutor()
    21 for url in urls:
    22     f = pool.submit(get_data,url)#提交任务
    23     f.add_done_callback(parser_data)#绑定一个回调函数
    24 
    25     # data = f.result()#获取结果
    26     # parser_data(data)#解析结果
    View Code
    异步回调例子二
     1 from concurrent.futures import ProcessPoolExecutor
     2 import time,random
     3 
     4 def task(num):
     5     time.sleep(random.randint(1,3))
     6     # print(num ** 2)
     7     return num ** 2
     8 
     9 if __name__ == '__main__':
    10     pool = ProcessPoolExecutor()
    11 
    12     fs = []
    13     for i in range(6):
    14         f = pool.submit(task,i) # 以异步方式发起任务
    15         #print(f.result()) # 获取任务的执行结果 即 task函数的返回值
    16         #  会把异步变为同步  并行变成串行
    17         fs.append(f)
    18 
    19     # 方式1
    20     # 按照顺序来获取结果 将导致 一些任务可能已经完成了但是 没有及时获取到结果
    21     # 例如 第二个任务先执行完毕 但是必须要等到第一个执行结束才能拿到结果
    22     # for f in fs:
    23     #     print(f.result())
    24 
    25     # shutdown   关闭进程池  会阻塞直到所有进程任务全部执行完毕
    26     pool.shutdown(wait=True)
    27     for f in fs:
    28         print(f.result())
    29 
    30     # 关闭之后不能提交新任务
    31     # pool.submit(task,10)
    32 
    33     print("Over")
    View Code
    直接使用线程或者进程发起异步View Code
  • 相关阅读:
    Codeforces Round #437 (Div. 2, based on MemSQL Start[c]UP 3.0
    Codeforces 294C 组合数学
    Educational Codeforces Round 40 (Rated for Div. 2)
    第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛
    天梯赛和蓝桥杯省赛训练
    莫队算法
    牛客练习赛13
    51NOD-1391 预处理dp
    AtCoder Regular Contest 092
    大二下学期赛季
  • 原文地址:https://www.cnblogs.com/zhangzhechun/p/10511793.html
Copyright © 2011-2022 走看看