Как запустить несколько экземпляров одного и того же класса асинхронно? - PullRequest
1 голос
/ 22 апреля 2020

Мне нужно, чтобы многие агенты подключались к разным сокетам моего локального сервера, чтобы они могли независимо читать и отправлять на сервер. Пока у меня есть это:

import json
import asyncio

class Agent():
    def __init__(self, user, pw):
        self.user = user
        self.pw = pw

        # Store host and port
        self.host, self.port = "localhost", 12300

        self.connect()

    async def connect(self):
        # Create asynchronous socket reader and writer
        self.reader, self.writer = await asyncio.open_connection(self.host,
                                                                 self.port)

        request = <some_json>

        # Create and send authentication request
        self.writer.write(request)
        await self.writer.drain()

        response = await self.reader.read(1000)
        response = json.loads(response.decode().split("\0")[0])

        if response["content"]["result"] == "ok":
            print("Connection Succesful")
        else:
            print("Connection Failed")

        await self.listen()

    async def receive_msg(self):
        """
        Waits for a message from the server and returns it.
        """
        msg = await self.reader.readuntil(b"\0")
        msg = msg.decode().split("\0")[0]

        # In case a message is received, parse it into a dictionary.
        if len(msg) > 1:

            return json.loads(msg)
        else:
            print("Retry receiving message...")
            return self.receive_msg()

    async def listen(self):
        """
        Listens for output from server and writes if anything is received
        """

        while True:
            msg = await self.receive_msg()
            print("Message received", self.user)


a_list = []

loop = asyncio.get_event_loop()

for i in range(15):
    a_list.append(Agent(f"agentA{i}", "1").connect())

loop.run_until_complete(asyncio.gather(*a_list))

Из-за того, как работает asyncio, я думаю, что это единственный способ выполнить это асинхронно. Но я хотел бы иметь возможность заставить асинхронно запускать __init__ вместо того, чтобы бросать функцию connect в l oop, если это возможно. По сути, я хотел бы сделать следующее:

a_list = []

loop = asyncio.get_event_loop()

for i in range(15):
    a_list.append(Agent(f"agentA{i}", "1"))

loop.run_until_complete(asyncio.gather(*a_list))

Я думаю, это имеет больше смысла, но я не могу понять, как это сделать. Я ошибаюсь или есть лучший способ сделать это?

1 Ответ

1 голос
/ 23 апреля 2020

Вы не можете сделать __init__ asyn c, но вы можете сделать Agent экземплярами ожидаемыми. Для этого определите метод __await__ magi c:

class Agent:
    def __init__(self, user, pw):
        self.user = user
        self.pw = pw
        self.host, self.port = "localhost", 12300

    def __await__(self):
        yield from self.connect().__await__()

Это лучшее из обоих миров: ваша функция __init__ остается син c, а экземпляры Agent допустимые аргументы для таких функций, как asyncio.gather().

...