【问题标题】:sys:1: RuntimeWarning: coroutine was never awaitedsys:1: RuntimeWarning: 从未等待协程
【发布时间】:2019-09-09 10:22:17
【问题描述】:

我正在尝试编写一个请求处理程序来帮助我以异步模式发送请求。当我使用 Ctrl+D 或 exit() 关闭 python 终端时,它会提示

显示sys:1: RuntimeWarning: coroutine was never awaited

import asyncio
import urllib.request
import json 

class RequestHandler:
    def SendPostRequest(method="post",url=None, JsonFormatData={}):
        # Encode JSON
        data =json.dumps(JsonFormatData).encode('utf8')
        # Config Request Header
        req = urllib.request.Request(url)
        req.add_header('Content-Type', 'application/json')      
        # Send request and wait the response
        response = urllib.request.urlopen(req,data=data)    
        return response 

    async def AsyncSend(method="post",url=None, JsonFormatData=None):
        if method == "post":
            loop = asyncio.get_event_loop()
            task = loop.create_task(SendPostRequest(method="post",url=url,JsonFormatData=JsonFormatData))

###################################
# Example
##### In main python terminal, i run like this:
# from RequestHandler import * 
# RequestHandler.AsyncSend(method="post",url="xxxxxx", JsonFormatData={'key':'value'} )

当我点击 Ctrl+D 时,它会提示

sys:1: RuntimeWarning: coroutine 'RequestHandler.AsyncSend' was never awaited

我会忽略它吗?我不想打电话给await,因为我不在乎这个过程是否成功。

在这个链接“https://xinhuang.github.io/posts/2017-07-31-common-mistakes-using-python3-asyncio.html”中,它说“要在没有等待的情况下执行异步任务,请使用 loop.create_task() 和 loop.run_until_complete()”,那是不是错了?

【问题讨论】:

    标签: python-3.x python-asyncio coroutine


    【解决方案1】:

    我认为您将 JS 异步 API 与 Python 混淆了。在 Python 中,当您调用协程函数时,它会返回一个协程(类似于武装生成器),但不会将其安排在事件循环中。 (即不运行/消耗它)

    你有两个选择:

    1) 您可以通过await 或更早的yield from 等待它。

    2) 你可以asyncio.create_task(coroutine_function())。这相当于在 JS 中调用一个 Promise 而不给它一个处理程序或等待它。

    您看到的警告是告诉您协程没有运行。它只是被创建,而不是被消费。

    至于您的代码,有两个错误。首先 urllib 是一个阻塞库,你不能从中创建任务,也不能异步运行,看看aiohttp.ClientSession吧。

    其次,您看到的警告可能是由您同步调用AsyncSend 引起的(没有等待它)。同样,在 JS 中这可能很好,因为 JS 中的所有内容都是异步的。在 Python 中,您应该使用我上面提到的两种主要方法之一。

    如果您坚持使用阻塞库,您可以在不同的线程上运行它,这样您就不会阻塞事件循环。正如 Cloudomation 提到的,要做到这一点。你应该使用asyncio.run_in_executor(None, lambda: your_urllib_function())

    【讨论】:

      【解决方案2】:

      试试这个代码:

      class RequestHandler:
          def SendPostRequest(self, method="post", url=None, JsonFormatData={}):
              # Encode JSON
              data =json.dumps(JsonFormatData).encode('utf8')
              # Config Request Header
              req = urllib.request.Request(url)
              req.add_header('Content-Type', 'application/json')      
              # Send request and wait the response
              response = urllib.request.urlopen(req,data=data)    
              return response 
      
          async def Send(self, method="post", url=None, JsonFormatData=None):
              if method == "post":
                  bound = functools.partial(self.SendPostRequest, method="post", url=url, JsonFormatData=JsonFormatData)
                  loop = asyncio.get_event_loop()
                  await loop.run_in_executor(None, bound)
      
          def SendAsync(self):
              loop = asyncio.get_event_loop()
              loop.create_task(self.Send())
      

      【讨论】:

      • 但我需要将其设为异步函数。
      • SendPostRequest 似乎是一个在后台使用loop.create_task 调用的异步函数。同步调用AsyncSend会调度任务并立即退出。
      • "TypeError: a coroutine is expected, got "
      • @Question-erXDD 我之前的回答有误,请查看我更新后的回答
      • 谢谢,在您的大力帮助下我也解决了这个问题,如果需要,只需添加“def __init__(self):”
      猜你喜欢
      • 2018-10-26
      • 2021-10-22
      • 2019-12-15
      • 2021-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      • 2020-10-10
      相关资源
      最近更新 更多