【问题标题】:python asyncio having trouble with running two infinite functions asynchronouslypython asyncio 无法异步运行两个无限函数
【发布时间】:2022-04-11 16:56:02
【问题描述】:

所以我一直在尝试同时运行两个功能,但除非我停止另一个,否则其中一个似乎永远无法工作。第一个功能旨在每 30 秒发送一封电子邮件(功能经过自身测试并且有效)第二个功能是每 5 秒打印一个简单的语句。因此,在我看到每 6 个“Hello Worlds”语句之后,我应该收到一封电子邮件。但是,除非我在运行函数中实现一些东西来阻止它,比如“10 秒后结束”,否则我永远不会收到电子邮件。我希望这两个功能无限地继续(如果可能的话不会崩溃)。任何帮助表示赞赏。

async def timer():
    now = time.time()
    end = now + 30
    #sendmail(name, filepath + "\\" + name, receiver)
    while True:
        if time.time() >= end:
            sendmail(name, filepath + "\\" + name, receiver)
            now = time.time()
            end = now + 30

async def runs():
    while True:
        print("Hello World")
        time.sleep(5)


loop = asyncio.get_event_loop()
loop.create_task(runs())
loop.create_task(timer())
loop.run_forever()

此外,如果有人能够使用多处理或线程模块完成任务,我会很想看看它是如何完成的,因为我已经尝试过并且都失败了。 我尝试过的示例:

t1 = threading.Thread(target=timer)
t2 = threading.Thread(target=runs)
t1.start()
t2.start()

【问题讨论】:

  • async 提供合作并发。 timer 不是合作编写的 - 它从不暂停,例如通过asyncio.sleep(0).
  • 理想情况下,您还需要一个可等待的sendmail 版本。

标签: python-3.x asynchronous python-asyncio python-multiprocessing python-multithreading


【解决方案1】:

Python 的async 协程用于合作 并发。这意味着协程必须主动允许其他人运行。对于简单的情况,使用await asyncio.sleep 来暂停当前协程并运行其他协程。

async def timer():
    while True:
        await asyncio.sleep(30)
        sendmail(name, filepath + "\\" + name, receiver)

async def runs():
    while True:
        print("Hello World")
        await asyncio.sleep(5)

async def main():
    await asyncio.gather(timer(), runs())

asyncio.run(main())

值得注意的是,不要使用time.sleep - 这会阻塞整个线程,这意味着当前协程以及事件循环和所有其他协程
同样,避免任何运行时间较长的同步代码——asyncio 在同步代码运行时无法切换到其他协程。如果需要,请使用 asyncio 帮助程序在线程中运行同步代码,例如asyncio.to_threadloop.run_in_executor

async def timer():
    next_run = time.time()
    while True:
        # run blocking function in thread to keep event-loop free
        await asyncio.to_thread(sendmail, name, filepath + "\\" + name, receiver)
        # pause to run approx every 30 seconds
        await asyncio.sleep(next_run - time.time())
        next_run += 30

【讨论】:

  • 所以澄清一下,一旦 runs() 到达“await asyncio.sleep(5)”,它会切换到 timer() 函数 5 秒吗?
  • 一旦runs 到达asyncio.sleep(5)runs 将暂停 5 秒。与此同时,timer 或其他协程可以根据需要运行。
  • 宫城先生,最后一行不应该是asyncio.run(asyncio.gather(...))吗?它的编写方式,任何一个协程中的异常都会静默传递。
  • @user4815162342 asyncio.run 仅适用于协程; asyncio.gather 仅提供 Future,而不是协程。两者不兼容。
  • 哎呀,我一直忘记asyncio.run 的那个(恕我直言任意且不必要的)限制。在任何地方都需要协程的 curio/trio 概念在 asyncio 中不起作用,即使是一些最基本的实用程序,如 gather,也会返回期货。无论如何,感谢您的编辑!
【解决方案2】:

您可以使用 await asycio.sleep() 进行异步等待

import asyncio


async def timer():
    while True:
        
        print("email sent")
        await asyncio.sleep(30)


async def runs():
    while True:
        print("Hello World")
        await asyncio.sleep(5)

loop = asyncio.get_event_loop()
loop.create_task(timer())
loop.create_task(runs())
loop.run_forever()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    • 2020-11-02
    • 2022-12-19
    • 1970-01-01
    相关资源
    最近更新 更多