python协程coroutine

Python 协程Coroutine 定义 协程,又称微线程,纤程。英文名Coroutine。通过 async/await 语法进行声明。需要 Python 3.7+ 特点 协程的特点在于是一个线程执行,可以处理IO密集型程序的效率问题,但是处理CPU密集型不是它的长处,如要充分发挥CPU利用率可以结合多进程+协程。 优势 最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。 第二大优势就是不需要多线程的锁机制,因.. 阅读详情

从爬虫说起,这是一个同步方法

import time

def crawl_page(url):
    print('crawling {}'.format(url))
    sleep_time = int(url.split('_')[-1])
    time.sleep(sleep_time)
    print('OK {}'.format(url))

def main(urls):
    for url in urls:
        crawl_page(url)

%time main(['url_1', 'url_2', 'url_3', 'url_4'])
crawling url_1
OK url_1
crawling url_2
OK url_2
crawling url_3
OK url_3
crawling url_4
OK url_4
Wall time: 10.1 s

nest_asyncio模块允许在已经有一个运行中的事件循环的环境(如 Jupyter Notebook)中使用asyncio.run()。

!pip install nest_asyncio
Collecting nest_asyncio
  Downloading https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl
Installing collected packages: nest-asyncio
Successfully installed nest-asyncio-1.6.0


WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='pypi.org', port=443): Read timed out. (read timeout=15)")': /simple/nest-asyncio/
WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ConnectTimeoutError(<pip._vendor.urllib3.connection.VerifiedHTTPSConnection object at 0x000001F1788907F0>, 'Connection to pypi.org timed out. (connect timeout=15)')': /simple/nest-asyncio/

这样,你就大概看懂了协程是怎么用的吧。不妨试着跑一下代码,欸,怎么还是 10 秒?

import asyncio
import nest_asyncio

# 允许在 Jupyter Notebook 中运行 asyncio.run()
nest_asyncio.apply()

async def crawl_page(url):
    print('crawling {}'.format(url))
    sleep_time = int(url.split('_')[-1])
    await asyncio.sleep(sleep_time)
    print('OK {}'.format(url))

async def main(urls):
    for url in urls:
        await crawl_page(url)

%time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4']))
crawling url_1
OK url_1
crawling url_2
OK url_2
crawling url_3
OK url_3
crawling url_4
OK url_4
Wall time: 10.1 s

接下来要讲的协程中的一个重要概念,任务(Task)

import asyncio

async def crawl_page(url):
    print('crawling {}'.format(url))
    sleep_time = int(url.split('_')[-1])
    await asyncio.sleep(sleep_time)
    print('OK {}'.format(url))

async def main(urls):
    tasks = [asyncio.create_task(crawl_page(url)) for url in urls]
    for task in tasks:
        await task

%time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4']))

crawling url_1
crawling url_2
crawling url_3
crawling url_4
OK url_1
OK url_2
OK url_3
OK url_4
Wall time: 4.02 s

还有另一种写法

import asyncio

async def crawl_page(url):
    print('crawling {}'.format(url))
    sleep_time = int(url.split('_')[-1])
    await asyncio.sleep(sleep_time)
    print('OK {}'.format(url))

async def main(urls):
    tasks = [asyncio.create_task(crawl_page(url)) for url in urls]
    # 使用*task 来解包
    await asyncio.gather(*tasks)

%time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4']))

crawling url_1
crawling url_2
crawling url_3
crawling url_4
OK url_1
OK url_2
OK url_3
OK url_4
Wall time: 4.03 s

解密协程

import asyncio

async def worker_1():
    print('worker_1 start')
    await asyncio.sleep(1)
    print('worker_1 done')

async def worker_2():
    print('worker_2 start')
    await asyncio.sleep(2)
    print('worker_2 done')

async def main():
    print('before await')
    await worker_1()
    print('awaited worker_1')
    await worker_2()
    print('awaited worker_2')

%time asyncio.run(main())
before await
worker_1 start
worker_1 done
awaited worker_1
worker_2 start
worker_2 done
awaited worker_2
Wall time: 3.05 s
  • asyncio.run(main())执行,程序进入main()函数,事件循环开启,同时创建task1和task2任务等待运行,接着输出 ‘before await’。
  • await task1执行,事件调度器调度worker_1,worker_1输出 ‘worker_1 start’ 后因await asyncio.sleep(1)切出,接着调度worker_2,worker_2输出 ‘worker_2 start’ 后因await asyncio.sleep(2)切出,此过程时间极短,随后事件调度暂停。
  • 一秒钟后,worker_1的sleep完成,事件调度器将控制权传回task_1,输出 ‘worker_1 done’,task_1完成从事件循环退出,await task1完成,主任务输出 ‘awaited worker_1’,在await task2处继续等待。
  • 两秒钟后,worker_2的sleep完成,事件调度器将控制权传回task_2,输出 ‘worker_2 done’,task_2完成从事件循环退出,主任务输出 ‘awaited worker_2’,协程全任务结束,事件循环结束。
import asyncio

async def worker_1():
    print('worker_1 start')
    await asyncio.sleep(1)
    print('worker_1 done')

async def worker_2():
    print('worker_2 start')
    await asyncio.sleep(2)
    print('worker_2 done')

async def main():
    task1 = asyncio.create_task(worker_1())
    task2 = asyncio.create_task(worker_2())
    print('before await')
    await task1
    print('awaited worker_1')
    await task2
    print('awaited worker_2')

%time asyncio.run(main())

before await
worker_1 start
worker_2 start
worker_1 done
awaited worker_1
worker_2 done
awaited worker_2
Wall time: 2.03 s

如果我们想给某些协程任务限定运行时间,一旦超时就取消,又该怎么做呢

worker_1 正常运行,worker_2 运行中出现错误,worker_3 执行时间过长被我们 cancel 掉了,这些信息会全部体现在最终的返回结果 res 中。

import asyncio

async def worker_1():
    await asyncio.sleep(1)
    return 1

async def worker_2():
    await asyncio.sleep(2)
    return 2 / 0

async def worker_3():
    await asyncio.sleep(3)
    return 3

async def main():
    task_1 = asyncio.create_task(worker_1())
    task_2 = asyncio.create_task(worker_2())
    task_3 = asyncio.create_task(worker_3())

    await asyncio.sleep(2)
    task_3.cancel()

    res = await asyncio.gather(task_1, task_2, task_3, return_exceptions=True)
    print(res)

%time asyncio.run(main())

[1, ZeroDivisionError('division by zero'), CancelledError()]
Wall time: 2.01 s

协程实现生产者消费者

import asyncio
import random

async def consumer(queue, id):
    while True:
        val = await queue.get()
        print('{} get a val: {}'.format(id, val))
        await asyncio.sleep(1)

async def producer(queue, id):
    for i in range(5):
        val = random.randint(1, 10)
        await queue.put(val)
        print('{} put a val: {}'.format(id, val))
        await asyncio.sleep(1)

async def main():
    queue = asyncio.Queue()

    consumer_1 = asyncio.create_task(consumer(queue, 'consumer_1'))
    consumer_2 = asyncio.create_task(consumer(queue, 'consumer_2'))

    producer_1 = asyncio.create_task(producer(queue, 'producer_1'))
    producer_2 = asyncio.create_task(producer(queue, 'producer_2'))

    await asyncio.sleep(10)
    consumer_1.cancel()
    consumer_2.cancel()
    
    await asyncio.gather(consumer_1, consumer_2, producer_1, producer_2, return_exceptions=True)

%time asyncio.run(main())

producer_1 put a val: 8
producer_2 put a val: 10
consumer_1 get a val: 8
consumer_2 get a val: 10
producer_1 put a val: 5
producer_2 put a val: 1
consumer_2 get a val: 5
consumer_1 get a val: 1
producer_1 put a val: 6
producer_2 put a val: 6
consumer_1 get a val: 6
consumer_2 get a val: 6
producer_1 put a val: 10
producer_2 put a val: 6
consumer_2 get a val: 10
consumer_1 get a val: 6
producer_1 put a val: 9
producer_2 put a val: 9
consumer_1 get a val: 9
consumer_2 get a val: 9
Wall time: 10 s

crawler 豆瓣

!pip install aiohttp
Requirement already satisfied: aiohttp in d:\sdk\anaconda3\lib\site-packages (3.8.6)
Requirement already satisfied: asynctest==0.13.0; python_version < "3.8" in d:\sdk\anaconda3\lib\site-packages (from aiohttp) (0.13.0)
Requirement already satisfied: typing-extensions>=3.7.4; python_version < "3.8" in d:\sdk\anaconda3\lib\site-packages (from aiohttp) (3.7.4.3)
Requirement already satisfied: multidict<7.0,>=4.5 in d:\sdk\anaconda3\lib\site-packages (from aiohttp) (6.0.5)
Requirement already satisfied: charset-normalizer<4.0,>=2.0 in d:\sdk\anaconda3\lib\site-packages (from aiohttp) (3.3.2)
Requirement already satisfied: aiosignal>=1.1.2 in d:\sdk\anaconda3\lib\site-packages (from aiohttp) (1.3.1)
Requirement already satisfied: yarl<2.0,>=1.0 in d:\sdk\anaconda3\lib\site-packages (from aiohttp) (1.9.4)
Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in d:\sdk\anaconda3\lib\site-packages (from aiohttp) (4.0.3)
Requirement already satisfied: attrs>=17.3.0 in d:\sdk\anaconda3\lib\site-packages (from aiohttp) (19.1.0)
Requirement already satisfied: frozenlist>=1.1.1 in d:\sdk\anaconda3\lib\site-packages (from aiohttp) (1.3.3)
Requirement already satisfied: idna>=2.0 in d:\sdk\anaconda3\lib\site-packages (from yarl<2.0,>=1.0->aiohttp) (2.8)
import asyncio
import aiohttp
from bs4 import BeautifulSoup

async def fetch_content(url):
    async with aiohttp.ClientSession(headers=None, connector=aiohttp.TCPConnector(ssl=False)) as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    url = "https://movie.douban.com/cinema/later/beijing/"
    init_page = await fetch_content(url)
    init_soup = BeautifulSoup(init_page, 'html.parser')

    movie_names, urls_to_fetch, movie_dates = [], [], []

    all_movies = init_soup.find('div', id="showing-soon-list")
    if all_movies is None:
        return
    for each_movie in all_movies.find_all('div', class_="item"):
        all_a_tag = each_movie.find_all('a')
        all_li_tag = each_movie.find_all('li')

        movie_names.append(all_a_tag[1].text)
        urls_to_fetch.append(all_a_tag[1]['href'])
        movie_dates.append(all_li_tag[0].text)

    tasks = [fetch_content(url) for url in urls_to_fetch]
    pages = await asyncio.gather(*tasks)

    for movie_name, movie_date, page in zip(movie_names, movie_dates, pages):
        soup_item = BeautifulSoup(page, 'html.parser')
        img_tag = soup_item.find('img')
        if img_tag is not None:
            print('{} {} {}'.format(movie_name, movie_date, img_tag['src']))

%time asyncio.run(main())
Wall time: 1.38 s
理解Python的协程(Coroutine) 本文就生成器和协程做了一些学习、探究和总结,不过并没有做过多深入深入的研究。权且作为入门到一个笔记,之后将会尝试自己实现一下异步API,希望有助于理解学习。 阅读详情

相关推荐

Python中协程(coroutine)详解

正常函数怎么写就怎么写,在def前面加上async即可。

python56123的博客 1236

Python—协程(Coroutine)

协程概念和代码使用

蓝魔的博客 6279

python协程多任务爬取下载数据

【代码】python协程多任务爬取下载数据。

WonderfulUUZ的博客 442

汇川AM402、H3U和上位机C#ModebusTcp通讯

目录一、测试任务二、测试环境三、PLC工程1、组态配置2、ip地址、端口号 3、全局变量定义四、C#端Winform程序创建1创建主界面 2、创建子窗口 3、运行生成,界面效果4、Modebus协议说明5、Modebus操作说明六、测试1、寄存器读测试 2、MW1300寄存器的BIT位3、写寄存器测试4、PLC断电或者断网 七、工程下载连接1、PLC作为ModebusTCP端,端口号都是502,PC端上位机软件作为TcpClient去连接多台PLC。PC端读写PLC寄存器。2、PC端在有的PLC断电、断网的

panjinliang066333的博客 2万+

EDA工具安装第一步:Synopsys Installer的配置与图形化界面使用详解

本文详细解析了EDA工具安装的关键第一步——Synopsys Installer的配置与使用。文章阐述了其作为统一部署管理器和依赖协调者的核心作用,并分步详解了如何通过图形化界面高效安装EDA工具,同时介绍了命令行批处理等进阶技巧,旨在帮助工程师快速搭建稳定的芯片设计环境。

zeta9的博客 342

Python 协程(Coroutine)的使用

在 Python 中,协程是通过async def关键字定义的。这种函数定义会返回一个协程对象,而不是直接执行函数的代码。

[ta叫我小白]的专栏 1015

Linux系统安装AutoDockTools、AutoGrid和AutoDock并实现分子对接(详细讲解)

linux系统为centos7.0 按照下面操作安装AutoDockTools(MGLTools) 1. 下载安装包,链接(https://ccsb.scripps.edu/mgltools/downloads/),我的linux系统是64位,下载红色标记源代码,拷贝入linux目标文件夹下。 2. shell终端进行安装: 1. 终端进入安装包所在文件夹,并获取root权限;赋予代码安装权限; cd /home/... #目标文件夹,根据目标程序文件位置进行更改 su #获

carlos_zhao的博客 1万+

Python编程:协程coroutine

关于协程协程 coroutine 微线程,一种用户态的轻量级线程好处: 无需线程上下文切换的开销 无需原子操作锁定及同步的开销 方便切换控制流,简化编程模型 高并发+高扩展+低成本,一个cup支持上万的协程都不是问题缺点: 无法利用多核资源,协程的本质是单线程, 进程阻塞blocking操作如io时会阻塞整个程序单线程下实现并发效果:遇到io就切换服务器处理模型: 1.一个进程处理一

彭世瑜的博客 1450

13、基因相似性度量的相关性及特征选择研究

本文研究了基因相似性度量和特征选择在生物学中的应用,详细介绍了GO术语相似性度量的多种方法,包括语义度量和路径长度度量,并分析了不同方法在酵母和人类数据集上的表现。研究发现,Avg-sum方法和基于路径长度的度量在多数情况下效果较好。此外,通过晚期辐射毒性预测的案例研究,探讨了特征选择的重要性及可能面临的过拟合和噪声干扰问题,并提出了相应的解决策略。

js777的博客 127

[SaaS] 阿里妈妈-万相营造

有controlnet的介入,我们是默认controlnet会介入,在inapinting时会把带有商品的画布做一点扩充,然后走inapinting和controlnet,其实也做了一点outpainting的工作。基于阿里妈妈营销平台,提供从图文到视频再到落地页的素材级智能化创意支持,是您营销创意数字资产累积和升值的阵地,最大化提升营销的效率和效果。目前看来抠图基本都是sam了,现在weshop也是,都有一个预扣好的主体,但是一点进去也会重新sam。atomovideo->图生视频。

liguandong 524

Python中协程(Coroutine)的使用和注意点

0. 协程的优势 在Lua中有协程,在Python里也有协程(Coroutine)。那为什么会需要协程,协程的好处有哪些? 1. 分片计算(sliced calculating) 我们可以把一个原本很复杂的计算分成若干断,每次算一小段,然后每次获得一小部分的结果。这样就会降低卡顿现象的出现概率。 2. 手动暂停和恢复 这个好处就是,有一些东西我可以做到一半,当需要其他函数支持的时候,可以

tab_space的博客 5701

【异常】XXL-job触发调度:address:http://192.168.x.x:x/ code:500 msg:xxl-rpc remoting error(connect timed out)

XXL-JOB调度任务失败分析:调度中心(10.254.234.80)与执行器(192.168.x.x)连接超时,返回500错误。主要原因是网络不通或执行器异常:1.网络不通可能由防火墙或网段隔离导致;2.执行器未启动或端口未监听;3.地址配置错误。解决方案:1.关闭代理使用内网;2.测试网络连通性和端口可用性;3.检查执行器进程状态和端口监听情况;4.核对执行器地址配置;5.必要时配置防火墙规则放行端口。

奶爸的编程之路,也就一周冷个三天 414

python coroutine协程

python3.7 In [8]: async def funcc(): ...: print('2333') ...: return '2333' In [14]: x = funcc() In [15]: try: ...: x.send(None) ...: except StopIteration as exc: .....

hunyxv的博客 382

【五分钟论文笔记】Vision Banana:图像生成器成为通用视觉学习器

图像生成训练可以像 LLM 预训练一样,让模型学习强大且通用的视觉表示感知即生成——将视觉任务输出参数化为 RGB 图像,是一种优雅且强大的统一框架视觉理解能力可以在不牺牲生成能力的情况下获得——两者可以共存于同一个模型。

专注:太空算力、AI infra、异构调度、大模型成本工程 232

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

python协程使用场景_详细解读tornado协程(coroutine)原理

tornado中的协程是如何工作的协程定义Coroutines are computer program components that generalize subroutines for nonpreemptive multitasking, by allowing multiple entry points for suspending and resuming execution at c...

weixin_39946996的博客 488

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Python 深入理解协程(Coroutine)

本文将深入理解协程,从生成器到协程的演进开始,逐步探索协程的多种定义方式、await关键字的奥秘以及协程嵌套与链式调用的实践。 

呱牛 Just do IT 427

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

python3 协程_Python3 异步神器-协程(Coroutine)

什么是协程协程(Coroutine),又称微线程,纤程。通常我们认为线程是轻量级的进程,因此我们也把协程理解为轻量级的线程即微线程。协程的作用是在执行函数A时可以随时中断去执行函数B,然后中断函数B继续执行函数A(可以自由切换)。这里的中断,不是函数的调用,而是有点类似CPU的中断。这一整个过程看似像多线程,然而协程只有一个线程执行。协程的优势执行效率极高,因为是子程序(函数)切换不是线程切换,由...

weixin_39553753的博客 439

python generator yield 协程 coroutine

参考生成器协程提高:现在还是看不懂 Python “黑魔法” 之 Generator Coroutines代码分析#!/usr/bin/env pythonimport timedef consumer(): r = '' while True: n = yield r print '[CONSUMER] Consuming ', n

stevewong的专栏 547

python3 协程 写同一个文件_python协程 -- 动态添加协程任务asyncio.run_coroutine_threadsafe...

使用asyncio.run_coroutine_threadsafe动态添加协程任务到事件循环中一. 官方文档根据asyncio的文档介绍,asyncio的事件循环不是线程安全的,一个event loop只能在一个线程内调度和执行任务,并且同一时间只有一个任务在运行,当程序调用get_event_loop获取event loop时,会从一个本地的Thread Local对象获取属于当前线程的eve...

weixin_39919089的博客 2200

Python协程(coroutine)

coroutine和generator的区别 generator是数据的产生者。即它pull data 通过 iteration,generator的作用是可以作为data pipeline使用. coroutine是数据的消费者。它push data into pipeline 通过 send;coroutine来做filter; 解释:通过send(value)方法将value作为y

每日运维 515

【python】协程(coroutine)

coroutine/task/future都是可await获取执行结果的,但await coroutine并不会创建task,会挂起同步等待await的协程执行完再回到当前协程继续执行,而await task/future时,会异步等待task完成。注意这里的执行指的是占用CPU计算,不包括等待阻塞等场景。1)直接await coroutine时,阻塞执行,两个协程各自sleep 1s,共用时2s+2)await task时,非阻塞执行,两个task各自sleep 1s,共用时1s+

atwdy的博客 1168

python3 协程 写法_理解Python的协程(Coroutine)

由于GIL的存在,导致Python多线程性能甚至比单线程更糟。GIL: 全局解释器锁(英语:Global Interpreter Lock,缩写GIL),是计算机程序设计语言解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行。[1]即便在多核心处理器上,使用 GIL 的解释器也只允许同一时间执行一个线程。于是出现了协程(Coroutine)这么个东西。协程: 协程,又称微线程,纤程,英...

weixin_39940154的博客 717

python3 协程 返回值_Python 协程(Coroutine)

什么是协程?knuth解释:协程就是多入多出的子程序,就是可以协同运行的程序。通常在Python中我们进行并发编程一般都是使用多线程或者多进程来实现的。对于计算型任务由于GIL的存在我们通常使用多进程来实现;而对于IO型任务我们可以通过线程调度来让线程在执行IO任务时让出GIL,从而实现表面上的并发。Python3.4中加入了asyncioPython3.5上提供了async/await语法层面的...

weixin_35651612的博客 1085

Python中的协程(Coroutine)

Python中的协程(Coroutine)

高效匠人 1383
上一篇: python迭代器生成器
下一篇: python用爬虫实战Future
悟空学编程
博客等级 码龄12年 32粉丝 123原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悟空学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值