2

I have an websocket server up and running fine using FastAPI.

However, when i am using those "await", i am getting some latency issues. At first, i though this had something to do with internet connection, or perhaps my linux server. But it appears to be that asyncio waits for other tasks.

Here is my code:

import asyncio
from pydantic import BaseModel

class UserClientWebSocket(BaseModel):
    id: str
    ws: WebSocket

    class Config:
        arbitrary_types_allowed = True



class ConnectionManager:
    def __init__(self):

        self.active_user_client_connections: List[UserClientWebSocket] = []
        self.collect_user_IDs = []




async def connect_the_user_client(self, websocket: WebSocket, THE_USER_ID):
    await websocket.accept()
    await self.send_message_to_absolutely_everybody(f"User: {THE_USER_ID} connected to server!")
    print("User: {} ".format(THE_USER_ID) + " Connected")
    if THE_USER_ID not in self.collect_user_IDs:
        self.collect_user_IDs.append(THE_USER_ID)
    else:
        await self.send_message_to_absolutely_everybody(f"Somebody connected with the same ID as client: {THE_USER_ID}")
        await self.send_message_to_absolutely_everybody("but Vlori is a nice and kind guy, so he wil not get kicked :)")
        self.collect_user_IDs.append(THE_USER_ID)
    self.active_user_client_connections.append(UserClientWebSocket(ws=websocket, id=THE_USER_ID))
    await self.show_number_of_clients()


async def function_one_send_message_to_absolutely_everybody(self, message: str):
    try:
        await asyncio.sleep(2)
        await asyncio.gather(*(conn.ws.send_text(message) for conn in self.active_webpage_client_connections))
        await asyncio.gather(*(conn.ws.send_text(message) for conn in self.active_user_client_connections))
    except:
        print("waiting")

async def function_two_send_personal_message_to_user(self, message: str, websocket: WebSocket):
    try:
        await websocket.send_text(message)
    except:
        print("waiting for task..")

... ... ... ... ...

and further down is the channel in which client connects:

@app.websocket("/ws/testchannel")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()

    try:
        while True:
            data = await websocket.receive_text()
            print_result = print("Received data: {} ".format(data))

            send_data_back_to_user = await websocket.send_text(f"you sent message: {data}")

          

    except WebSocketDisconnect as e:
        print("client left chat, error = ", e)

The code as it stands now works perfectly, and the performance is good! However, if i add an async def function under the "send_data_back_to_user" line such as this:

await connection_manager.function_one_send_message_to_absolutely_everybody(data)

Then there is a huge latency! why is that?

I am playing around and tried this:

@app.websocket("/ws/testchannel")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    try:
        while True:
            data = await websocket.receive_text()
            print_result = print("Received data: {} ".format(data))

            send_data_back_to_user = await websocket.send_text(f"you sent message: {data}")   # if i comment this line and the line underneath, and the speed is extremely fast!

   
            the_asyncio_loop = asyncio.get_event_loop()

            print_data_on_terminal = asyncio.gather(print_result)
            return_data_back_to_user = asyncio.gather(send_data_back_to_user)
            broadcast_msg = asyncio.gather(connection_manager.function_one_send_message_to_absolutely_everybody(data))

            run_all_loops_together = asyncio.gather(print_data_on_terminal, return_data_back_to_user, broadcast_msg)

            results = the_asyncio_loop.run_until_complete(run_all_loops_together)

            print(results)


    except WebSocketDisconnect as e:
        print("client left chat, error = ", e)

but gives me the error:

TypeError: An asyncio.Future, a coroutine or an awaitable is required

could someone help me with this?

thanks.

gigija3
  • 33
  • 2
  • 7
  • 1
    `await` gives other tasks time to run, on the same thread. If you're noticing a lot of lag after an `await` happens, you're likely trying to do too much work on the thread that asyncio is using. – Carcigenicate Oct 01 '20 at 13:33
  • But there is a solution to this? something such as async.gather or something ? If not, then what is the point of asyncio? – gigija3 Oct 01 '20 at 13:35
  • 1
    I think I may, but you're code may require significant refactoring to use ```asyncio.Queue```. Currently working on it - hold my beer. – jupiterbjy Oct 01 '20 at 13:37
  • Asyncio is for waiting on multiple IO resources at once, on a single thread. – Carcigenicate Oct 01 '20 at 13:39
  • At this stage, low latency is extremely important for my websocket and project, and if there is absolutely no possibility(i think it is tho), to reduce this asyncio.gather() or asyncio.future(), then i might need to consider using something else.. – gigija3 Oct 01 '20 at 13:49
  • 1
    You're awaiting ```asyncio.sleep(2)```. That's blocking 2 seconds without doing anything, design flaw. – jupiterbjy Oct 01 '20 at 14:08
  • I removed that, the same thing still happening. EDIT: i changed it to asyncio.sleep(0.1) and it works !!!!!!!!!!!!!!!!!!!!!!! – gigija3 Oct 01 '20 at 14:14
  • Why you need to sleep for nothing in first place? Don't get confused by unpredictable nature of IO operations - probably it is not solved yet. – jupiterbjy Oct 01 '20 at 14:20
  • some places i need to use that sleep, otherwise the server might "crash" when for example i disconnect 2 or multiple users at once from the server. – gigija3 Oct 01 '20 at 14:23

0 Answers0