sys:1:RuntimeWarning:从未等待协程

时间:2019-04-19 05:08:59

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

我正在尝试编写一个请求处理程序,以帮助我以异步模式发送请求。当我使用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()一起使用”,那是错误的吗?

2 个答案:

答案 0 :(得分:3)

我认为您正在将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())

答案 1 :(得分:1)

尝试以下代码:

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())