简体   繁体   English

这是使用Python`asyncio`协同程序的预期模式吗?

[英]Is this the intended pattern for using Python `asyncio` coroutines?

I'm trying to write a little concurrent stream handler with the Slack RTM API and I'm wondering if this is the most efficient use of Python coroutines. 我正在尝试用Slack RTM API编写一个小的并发流处理程序,我想知道这是否是Python协程的最有效使用。 The asyncio package has a ton of options but it's hard to determine what is the correct approach for the project and the documentation I think doesn't do a very good job of explaining what the advantages/disadvantages are to each. asyncio软件包有很多选项,但是很难确定项目的正确方法是什么,我认为文档并没有很好地解释每个方面的优点/缺点。

I think that I don't need to have the overhead of multiple threads here, and I need intercommunication between the async loops. 我认为我不需要在这里有多个线程的开销,我需要在异步循环之间进行相互通信。 Should I create a separate BaseEventLoop for each of my functions? 我应该为每个函数创建一个单独的BaseEventLoop吗?

Being Python, I think there is a near -deterministic answer here to this question ( There should be one-- and preferably only one --obvious way to do it ) but I'm afraid that adding all this asynchronous cruft may just make my code less performance than the completely sequential naive implementation. 作为Python,我认为这个问题There should be one-- and preferably only one --obvious way to do it一个接近确定性的答案( There should be one-- and preferably only one --obvious way to do it有一个 - There should be one-- and preferably only one --obvious way to do it )但是我担心添加所有这些异步伪装可能只是让我的代码性能低于完全顺序的天真实现。

# Is this the best way to communicate between coroutines? 
incoming_message_q = asyncio.Queue()

async def print_event():
    logging.info("Entering log loop")

    # Should this operate within it's own BaseEventLoop? 
    while True:
        event = await incoming_message_q.get()
        logging.info(event)

async def log_queue_status():
    while True:
        logging.info(incoming_message_q.qsize())
        await asyncio.sleep(5)

async def read_rtm_connection(client, q):
    if client.rtm_connect():
        logging.info("Successful Slack RTM connection")
        while True:

            # How do I make this part non-blocking?
            events = client.rtm_read()

            for event in events:
                logging.info("Putting onto the queue", event)
                if event["type"] == "presence_change":
                    await q.put(event)
                elif event["type"] == "message":
                    await q.put(event)
                else:
                    logging.info("Not sure what to do")

            await asyncio.sleep(0.1)
    else:
        logging.info("RTM connection failed.")

loop = asyncio.get_event_loop()
loop.create_task(print_event())
loop.create_task(log_queue_status())
loop.create_task(read_rtm_connection(client, incoming_message_q))
loop.run_forever()

If you want to interact with slack in an asyncio-friendly way, you're going to need to use a non-blocking API. 如果您想以asyncio友好的方式与slack进行交互,那么您将需要使用非阻塞API。 I'm not sure what you're currently using, but if it doesn't include any asyncio coroutines, it's probably not going to be easily integrated into asyncio, unless you run all the blocking calls in a background thread, via loop.run_in_executor . 我不确定你目前使用的是什么,但如果它不包含任何asyncio协同程序,它可能不会轻易集成到asyncio中,除非你在后台线程中运行所有阻塞调用,通过loop.run_in_executor The other option would be to actually convert all the underlying blocking I/O calls in the library to be non-blocking, which is generally a whole bunch of work. 另一种选择是将库中的所有底层阻塞I / O调用实际转换为非阻塞,这通常是一大堆工作。

The good news is that there is at least one library that has already done this work for you; 好消息是,至少有一个图书馆已经为您完成了这项工作; slacker-asyncio , which is a fork of slacker . slacker-asyncio ,是一个slacker的分支。 You should be able to use that to interact with the RTM API via coroutines. 您应该能够使用它通过协同程序与RTM API进行交互。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM