简体   繁体   中英

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. 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.

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?

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.

# 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. 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 . 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.

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 . You should be able to use that to interact with the RTM API via coroutines.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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