13

ここには非常に単純な問題があります。同時に多くのホストと通信する必要がありますが、各リクエストはかなり自己完結型であるため、同期は必要ありません。

そのため、スレッドをスパムするのではなく、非同期ソケットを使用することにしました。今、私は少し問題があります:

非同期のものは魅力のように機能しますが、100 のホストに接続し、100 のタイムアウト (タイムアウト = 10 秒) を取得すると、すべての接続が失敗したことを確認するためだけに 1000 秒待機します。

非ブロッキングソケット接続も取得する方法はありますか? ソケットはすでに nonBlocking に設定されていますが、connect() の呼び出しはまだブロックされています。

タイムアウトを減らすことは、受け入れられる解決策ではありません。

私はこれを Python で行っていますが、この場合、プログラミング言語はあまり重要ではないと思います。

本当にスレッドを使用する必要がありますか?

4

6 に答える 6

8

モジュールを使用しselectます。これにより、複数のノンブロッキング ソケットで I/O の完了を待つことができます。selectに関する詳細情報を次に示します。リンク先のページから:

C では、コーディングselectはかなり複雑です。Python では簡単ですが、C バージョンに十分近いので、Python で select を理解していれば、C でもほとんど問題はありません。

ready_to_read, ready_to_write, in_error = select.select(
                  potential_readers, 
                  potential_writers, 
                  potential_errs, 
                  timeout)

3 つのリストを渡しselectます。最初のリストには、読み取りを試みるすべてのソケットが含まれます。2 番目は書き込みを試みたいすべてのソケットで、最後 (通常は空のまま) はエラーをチェックしたいソケットです。ソケットは複数のリストに入る可能性があることに注意してください。呼び出しはブロックされselectていますが、タイムアウトを与えることができます。これは一般的には賢明なことです。特に理由がない限り、適切な長いタイムアウト (たとえば 1 分) を設定してください。

代わりに、3 つのリストを取得します。それらには、実際に読み取り可能、書き込み可能で、エラーになっているソケットがあります。これらの各リストは、渡された対応するリストのサブセット (空の可能性があります) です。また、ソケットを複数の入力リストに配置すると、(多くても) 1 つの出力リストにのみ配置されます。

ソケットが出力の読み取り可能なリストにある場合、recvそのソケットの が何かを返すということを、これまでにないほど確実にすることができます。書き込み可能リストについても同じ考えです。何かできるようになりsend ます。あなたが望むすべてではないかもしれませんが、何もないよりはましです。(実際には、適度に健全なソケットは書き込み可能として返されます。これは、アウトバウンド ネットワーク バッファー スペースが利用可能であることを意味します。)

「サーバー」ソケットがある場合は、それを potential_readers リストに入れます。読み取り可能なリストに表示された場合、accept は (ほぼ確実に) 機能します。他の誰かに接続するために新しいソケットを作成した場合は、それを potential_writers リストに入れます。書き込み可能リストに表示される場合は、接続されている可能性が十分にあります。

于 2009-07-30T11:21:52.717 に答える
7

残念ながら、バグを示すサンプル コードがないため、このブロックがどこから来たのかを確認するのは少し困難です。

彼は次のようなことをします:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setblocking(0)
s.connect(("www.nonexistingname.org", 80))

ソケット モジュールは内部で getaddrinfo を使用します。これは、特にホスト名が存在しない場合にブロック操作です。標準準拠の dns クライアントは、名前が実際に存在しないかどうか、または低速の dns サーバーが含まれているだけかどうかを確認するためにしばらく待機します。

解決策は、ip-addresses のみに接続するか、pydnsのようなノンブロッキング リクエストを許可する dns クライアントを使用することです。

于 2009-07-31T10:40:47.880 に答える
5

タイムアウトを設定するとソケットがブロックされるため、接続も並列化する必要があります。または、タイムアウトを設定できず、選択モジュールを使用できませんでした。

これは、 asyncoreモジュールのディスパッチャー クラスで実行できます。基本的なhttp クライアントの例を見てください。そのクラスの複数のインスタンスは、接続時に互いにブロックしません。これは、スレッドを使用して簡単に行うことができます。また、ソケット タイムアウトの追跡が容易になると思いますが、既に非同期メソッドを使用しているため、同じ道を歩むこともできます。

例として、以下は私のすべての Linux システムで動作します

import asyncore, socket

class client(asyncore.dispatcher):
    def __init__(self, host):
        self.host = host
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((host, 22))

    def handle_connect(self):
        print 'Connected to', self.host

    def handle_close(self):
        self.close()

    def handle_write(self):
        self.send('')

    def handle_read(self):
        print ' ', self.recv(1024)

clients = []
for i in range(50, 100):
    clients.append(client('cluster%d' % i))

asyncore.loop()

cluster50 ~ cluster100 には、応答しない、または存在しないマシンが多数あります。これにより、すぐに印刷が開始されます。

Connected to cluster50
  SSH-2.0-OpenSSH_4.3

Connected to cluster51
  SSH-2.0-OpenSSH_4.3

Connected to cluster52
  SSH-2.0-OpenSSH_4.3

Connected to cluster60
  SSH-2.0-OpenSSH_4.3

Connected to cluster61
  SSH-2.0-OpenSSH_4.3

...

ただし、これは、ブロックする必要がある getaddrinfo を考慮していません。DNS クエリの解決に問題がある場合は、すべてを待つ必要があります。おそらく、DNS クエリを自分で個別に収集し、非同期ループで IP アドレスを使用する必要があります。

asyncore よりも大きなツールキットが必要な場合は、Twisted Matrixをご覧ください。始めるのは少し大変ですが、Python 用に入手できる最高のネットワーク プログラミング ツールキットです。

于 2009-07-30T13:47:23.793 に答える
4

ねじって使用します。

これは Python で記述された非同期ネットワーク エンジンであり、多数のプロトコルをサポートしており、独自のプロトコルを追加できます。クライアントとサーバーの開発に使用できます。接続時にブロックされません。

于 2009-07-30T13:49:15.523 に答える
0

asyncoreモジュールを見ましたか? 必要なものだけかもしれません。

于 2009-07-30T11:15:18.767 に答える