如何在不同控制台或设备间传输变量?基于QTPY实现numpy数组跨设备高效传输的技术咨询
Great question! Using sendTextMessage() for numpy arrays is definitely inefficient—let’s dive into better approaches that play nicely with QtPy (or alternative tools) while keeping your chat feature working smoothly.
1. Use Qt WebSocket’s Binary Message Support (Best for QtPy Integration)
Qt’s QWebSocket has built-in support for binary messages via sendBinaryMessage() and the binaryMessageReceived signal—this is way faster than text-based transmission since it skips string encoding/decoding overhead.
Step 1: Serialize Numpy Arrays to Bytes
Numpy arrays can be directly converted to raw bytes with arr.tobytes(). To reconstruct the array on the receiving end, you’ll need to send metadata (dtype and shape) along with the raw data.
Sending Side Code:
import numpy as np import json from qtpy.QtWebSockets import QWebSocket def send_numpy_array(ws: QWebSocket, arr: np.ndarray): # Pack metadata (dtype and shape) into a JSON string meta = { "dtype": str(arr.dtype), "shape": arr.shape } meta_bytes = json.dumps(meta).encode("utf-8") # Send metadata length first (4-byte big-endian int) so receiver knows how much to read meta_length = len(meta_bytes).to_bytes(4, byteorder="big") # Combine metadata length, metadata, and array bytes into one binary message message = meta_length + meta_bytes + arr.tobytes() ws.sendBinaryMessage(message) # For chat messages, keep using sendTextMessage with a prefix to distinguish def send_chat_message(ws: QWebSocket, text: str): ws.sendTextMessage(f"CHAT:{text}")
Receiving Side Code:
import numpy as np import json from qtpy.QtWebSockets import QWebSocket def on_binary_message_received(message): # Extract metadata length (first 4 bytes) meta_length = int.from_bytes(message[:4], byteorder="big") # Extract and parse metadata meta_bytes = message[4:4+meta_length] meta = json.loads(meta_bytes.decode("utf-8")) # Extract array bytes and reconstruct the numpy array arr_bytes = message[4+meta_length:] arr = np.frombuffer(arr_bytes, dtype=np.dtype(meta["dtype"])) arr = arr.reshape(meta["shape"]) # Do something with the received array print(f"Received numpy array with shape {arr.shape}") def on_text_message_received(message): # Handle chat messages by checking the prefix if message.startswith("CHAT:"): chat_text = message[5:] print(f"Chat message: {chat_text}") # (Optional: Handle other text-based commands if needed) # Connect signals when setting up your WebSocket: # ws.binaryMessageReceived.connect(on_binary_message_received) # ws.textMessageReceived.connect(on_text_message_received)
2. Use Efficient Serialization Libraries (Like MsgPack)
For even more compact metadata (faster than JSON), use msgpack instead. It’s lightweight and designed for high-performance data serialization.
Example with MsgPack:
import msgpack def send_numpy_array_msgpack(ws: QWebSocket, arr: np.ndarray): data = { "type": "numpy_array", "dtype": str(arr.dtype), "shape": arr.shape, "data": arr.tobytes() } packed_data = msgpack.packb(data) ws.sendBinaryMessage(packed_data) def on_binary_message_received(message): unpacked = msgpack.unpackb(message) if unpacked.get("type") == "numpy_array": arr = np.frombuffer(unpacked["data"], dtype=np.dtype(unpacked["dtype"])) arr = arr.reshape(unpacked["shape"]) print(f"Received array (MsgPack): {arr.shape}")
3. Alternative: ZeroMQ for High-Performance Cross-Machine Transfer
If you need even better performance (especially for very large arrays or high-throughput scenarios), consider ZeroMQ. It’s a lightweight messaging library that supports multiple patterns (like PUB/SUB or REQ/REP) and integrates well with QtPy via QSocketNotifier to fit into Qt’s event loop.
Quick ZeroMQ Example:
import zmq import numpy as np # Sending side (PUB socket) context = zmq.Context() sender = context.socket(zmq.PUB) sender.bind("tcp://*:5555") # Listen on port 5555 def send_numpy_zmq(arr: np.ndarray): sender.send_array(arr) # pyzmq has built-in send_array/recv_array # Receiving side (SUB socket) receiver = context.socket(zmq.SUB) receiver.connect("tcp://your_remote_ip:5555") receiver.setsockopt_string(zmq.SUBSCRIBE, "") def receive_numpy_zmq(): arr = receiver.recv_array() return arr
To combine chat with ZeroMQ, you can use separate sockets: one for chat (text messages) and one for numpy arrays, or add a type field to your messages to distinguish between them.
Key Notes for Production:
- Large Arrays: For very big arrays, split them into chunks and send sequentially, then reassemble on the receiving end to avoid memory overload.
- Security: If communicating over untrusted networks, avoid
pickle(it’s insecure) and use encrypted WebSockets (wss://) or ZeroMQ with encryption. - Error Handling: Add checks for message integrity (e.g., checksums) and handle connection drops gracefully in your Qt app.
内容的提问来源于stack exchange,提问作者The Krehbiel

