Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would I combine two async libraries?

How would I go about combining two asyncio libraries in the same program?

For context, I wish to use the Discord api with aiohttp, both of which are async event loop driven. I may potentially want to add an async irc library to the mix, too.

However, I don't understand how they would be operated together. I believe that in theory I would implement the program such that all class instances utilise the same asyncio event loop instance, and then kludge all the run functions together into one, ultimately calling the event loop.

However, I would like to know if there is in general a more elegant way of doing this?

like image 543
Firnagzen Avatar asked Dec 15 '16 15:12

Firnagzen


People also ask

Is Python async concurrent?

The intended use of asyncio tasks is to allow independently running tasks to run 'concurrently' with other tasks within the same event loop.


1 Answers

As long as all the libraries use the same eventloop they will work together nicely. In this case it seems like all the libraries you choosed are based on asyncio (excetp gawel's IRC lib which is not available anymore). So there is no problem. There is a single eventloop (and no threads) and all is well.

The problem you face is that you will have several "servers" in the same event loop or more accuratly there is several coroutines that handle input from the outside world. One coroutine is handling the HTTP traffic and the other is handling the IRC "traffic". In pseudo-code, it can be translated to the following:

import asyncio



async def irc_server():
    async with irc_connect('irc.freenode.net#python-fr') as irc:
        async for message in irc:
            # do something useful with message

async def web_server():
    async with web_connect('localhost:8080') as web:
        async for request in web:
            # do something useful with request


loop = asyncio.get_event_loop()
loop.create_task(irc_server())
loop.create_task(web_server())

loop.run_forever()

As such, both coroutines have no way to communicate. To make the HTTP part communicate with the IRC part you have to share something between the two coroutines. In production it's prolly somekind of database but in pseudo code, it's a simple global. You will end up with something like that:

import asyncio


# value is shared between IRC and the web server.
value = None



async def irc_server():
    global value
    async with irc_connect('irc.freenode.net#python-fr') as irc:
        async for message in irc:
            # if message is echo, reply with the current value
            # otherwise store the message as value
            if message == 'echo':
                irc.send(value)
            else:
                value = message

async def web_server():
    global value
    async with web_connect('localhost:8080') as web:
        async for request in web:
            if request.path == 'echo':
                request.client.send(value)
            else:
                value = request.path  # this is silly but simple


loop = asyncio.get_event_loop()
loop.create_task(irc_server())
loop.create_task(web_server())

loop.run_forever()
like image 190
amirouche Avatar answered Sep 30 '22 19:09

amirouche