1

現在、クライアントとして機能する python クラスをプログラミングしています。メインスレッドをブロックしたくないので、パケットの受信は別のスレッドで行い、パケットが到着したらコールバック関数を呼び出します。

受信したパケットは、ブロードキャスト メッセージか、クライアントから送信されたコマンドに対する応答のいずれかです。コマンドを送信する関数は同期的で、応答が到着するまでブロックされるため、結果を直接返すことができます。

簡単な例:

import socket
import threading

class SocketThread(threading.Thread):
    packet_received_callback = None

    _reply = None
    _reply_event = threading.Event()

    def run(self):
        self._initialize_socket()

        while True:
            # This function blocks until a packet arrives
            p = self._receive_packet()

            if self._is_reply(p):
                self._reply = p
                self._reply_event.set()
            else:
                self.packet_received_callback(p)

    def send_command(self, command):
        # Send command via socket
        self.sock.send(command)

        # Wait for reply
        self._reply_event.wait()
        self._reply_event.clear()

        return self._process_reply(self._reply)

私が今直面している問題は、デッドロックで終了するため、コールバック関数でコマンドを送信できないことです (send_command は応答を待機しますが、パケットを受信するスレッドが実際にコールバックを実行しているため、パケットを受信できません)。関数)。

私の現在の解決策は、コールバック関数を呼び出すたびに新しいスレッドを開始することです。しかし、この方法では多くのスレッドが生成され、トラフィックが多い状況でパケットが同期的に処理されることを保証することが難しくなります。

よりエレガントなソリューションを知っている人はいますか、それとも正しい方法で進んでいますか?

ご協力いただきありがとうございます!

4

2 に答える 2

0

最近別のアイデアがありました。あなたがそれについてどう思うか教えてください。他の誰かが同様の問題を抱えていて、マルチスレッドを使用する必要がある場合に備えて、このような問題を解決するための一般的なアプローチにすぎません。

import threading
import queue

class EventBase(threading.Thread):
    ''' Class which provides a base for event-based programming. '''

    def __init__(self):
        self._event_queue = queue.Queue()

    def run(self):
        ''' Starts the event loop. '''

        while True:
            # Get next event
            e = self._event_queue.get()

            # If there is a "None" in the queue, someone wants to stop
            if not e:
                break

            # Call event handler
            e[0](*e[1], **e[2])
            # Mark as done
            self._event_queue.task_done()

    def stop(self, join=True):
        ''' Stops processing events. '''

        if self.is_alive():
            # Put poison-pill to queue
            self._event_queue.put(None)
            # Wait until finished
            if join:
                self.join()

    def create_event_launcher(self, func):
        ''' Creates a function which can be used to call the passed func in the event-loop. '''

        def event_launcher(*args, **kwargs):
            self._event_queue.put((func, args, kwargs))

        return event_launcher

そのようにそれを使用してください:

event_loop = eventbase.EventBase()
event_loop.start()

# Or any other callback
sock_thread.packet_received_callback = event_loop.create_event_launcher(my_event_handler)

# ...

# Finally
event_loop.stop()
于 2012-07-08T11:28:17.940 に答える
0

この質問に対する適切な答えは、解決しようとしている問題の詳細に大きく依存しますが、1 つの解決策を次に示します。

パケットを受信したらすぐにコールバック関数を呼び出すよりも、ソケット スレッドが受信したパケットを単純に保存し、パケットのポーリングを続行する方が理にかなっていると思います。次に、メイン スレッドに時間があれば、到着した新しいパケットをチェックして、それらに対処できます。

于 2012-07-05T21:20:46.530 に答える