Websocket scheme: callback or coroutine
Before formulating a trading strategy, it is typically necessary to retrieve data from the cex websocket interface. Therefore, adopting an excellent websocket data retrieval solution is essential. This article will compare two different implementations of websocket clients.
Difference between coroutine and callback
coroutine
In the context of websockets, coroutines can be utilized to efficiently handle asynchronous tasks. For instance, an asynchronous coroutine might be employed to manage incoming messages in a non-blocking manner. The following is a simple code example for setting up a server:
code example for setting up a server:
#!/usr/bin/env python
import asyncio
import websockets
# the websocket parameter is an instance of the WebSocketServerProtocol class,
# and it represents the communication channel between the server and
# a specific client connected to the WebSocket server
async def handler(websocket):
while True:
message = await websocket.recv()
print(message)
# Send the same message back to the client
await websocket.send(f"Server echoing: {message}")
# will be called each time a new client connects to the server
async def main():
# "" represents loopback interface that allows
# communication between processes on the same device.
async with websockets.serve(handler, "", 8001):
await asyncio.Future() # run forever
if __name__ == "__main__":
asyncio.run(main())
client-side code:
import asyncio
import websockets
async def connect_to_server():
uri = "ws://localhost:8001" # Change the URI to match your server address
async with websockets.connect(uri) as websocket:
while True:
message = input("Enter a message to send to the server (or 'exit' to quit): ")
if message.lower() == 'exit':
break
await websocket.send(message)
# Receive and print the echoed message from the server
response = await websocket.recv()
print(f"Received from server: {response}")
if __name__ == "__main__":
asyncio.run(connect_to_server())
callback
In the realm of websockets, callbacks may be employed to define functions that execute when specific events occur, such as receiving a message, establishing a connection, or encountering an error. Let’s now rewrite the client code using a callback scheme:
import websocket
def on_message(ws, message):
print(f"Received from server: {message}")
def connect_to_server():
uri = "ws://localhost:8001" # Change the URI to match your server address
ws = websocket.WebSocketApp(uri, on_message=on_message)
while True:
user_input = input("Enter a message to send to the server (or 'exit' to quit): ")
if user_input.lower() == 'exit':
break
ws.send(user_input)
ws.close()
if __name__ == "__main__":
connect_to_server()
Comparison
Callbacks are prevalent in older asynchronous code and may be utilized in systems heavily reliant on event-driven architectures. Coroutines, on the other hand, are the preferred approach in modern Python asynchronous programming, especially with the introduction of the async/await syntax.
I favor the coroutine scheme primarily because it provides a more elegant and readable solution for asynchronous programming, making it the preferred approach in modern Python development.