10

Python でのマルチスレッド サーバーとクライアントのソース コードを次に示します。

コードでは、クライアントとサーバーは、ジョブが終了した後に接続を閉じます。接続を維持し、同じ接続を介してより多くのデータを送信して、毎回ソケットを閉じたり開いたりするオーバーヘッドを回避したいと考えています。

次のコードはhttp://www.devshed.com/c/a/Python/Basic-Threading-in-Python/1/からのものです。

import pickle
import socket
import threading

# We'll pickle a list of numbers:
someList = [ 1, 2, 7, 9, 0 ]
pickledList = pickle.dumps ( someList )

# Our thread class:
class ClientThread ( threading.Thread ):

   # Override Thread's __init__ method to accept the parameters needed:
   def __init__ ( self, channel, details ):

      self.channel = channel
      self.details = details
      threading.Thread.__init__ ( self )

   def run ( self ):

      print 'Received connection:', self.details [ 0 ]
      self.channel.send ( pickledList )
      for x in xrange ( 10 ):
         print self.channel.recv ( 1024 )
      self.channel.close()
      print 'Closed connection:', self.details [ 0 ]

# Set up the server:
server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
server.bind ( ( '', 2727 ) )
server.listen ( 5 )

# Have the server serve "forever":
while True:
   channel, details = server.accept()
   ClientThread ( channel, details ).start()

import pickle
import socket
import threading

# Here's our thread:
class ConnectionThread ( threading.Thread ):

   def run ( self ):

      # Connect to the server:
      client = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
      client.connect ( ( 'localhost', 2727 ) )

      # Retrieve and unpickle the list object:
      print pickle.loads ( client.recv ( 1024 ) )

      # Send some messages:
      for x in xrange ( 10 ):
         client.send ( 'Hey. ' + str ( x ) + '\n' )

      # Close the connection
      client.close()

# Let's spawn a few threads:
for x in xrange ( 5 ):
   ConnectionThread().start()
4

3 に答える 3

20

接続ごとに新しいスレッドを生成することは、設計上の非常に悪い選択です。たくさんの接続に見舞われたらどうなりますか?

実際、ネットワーク IO を待機するためにスレッドを使用する価値はありません。プログラムは非常に複雑になり、スレッドでネットワークを待機しても待機が速くならないため、まったくメリットがありません。この場合、スレッドを使用するだけで負けます。

次のテキストは、python ドキュメントからのものです。

単一のプロセッサ上でプログラムに「一度に複数のこと」を実行させる方法は 2 つしかありません。マルチスレッド プログラミングは最も簡単で最も一般的な方法ですが、実際には複数のスレッドを使用しなくても、マルチスレッドのほぼすべての利点を利用できる、まったく異なる手法がもう 1 つあります。プログラムの大部分が I/O バウンドである場合にのみ、実際に実用的です。プログラムがプロセッサに依存している場合、プリエンプティブにスケジュールされたスレッドがおそらく本当に必要なものです。ただし、ネットワーク サーバーがプロセッサ バウンドになることはめったにありません。

そして、それがプロセッサにバインドされたサーバーの場合です。プロセッサの部分を実行するために、いつでも別のプロセス/スレッドを残すことができます。続き:

お使いのオペレーティング システムがその I/O ライブラリで select システム コールをサポートしている場合 (そしてほとんどすべてがサポートしている場合)、それを使用して一度に複数の通信チャネルを操作できます。I/O が「バックグラウンド」で行われている間に、他の作業を行っています。この戦略は、特に最初は奇妙で複雑に見えるかもしれませんが、多くの点で、マルチスレッド プログラミングよりも理解しやすく、制御しやすいです。

そのため、スレッドを使用する代わりに、ノンブロッキング入出力を使用します。リスト内のソケットを収集し、select.selectでイベント ループを使用して、どのソケットに読み取るデータがあるかを確認します。それを単一のスレッドで行います。

それを行うには、 twistedのような Python 非同期ネットワーク フレームワークを選択できます。これにより、多くの頭痛が解消されます。Twisted のコードは何年にもわたって改善されており、マスターするのに時間がかかるいくつかのまれなケースをカバーしています。

EDIT : 既存の非同期 IO ライブラリ (Twisted など) はすべて Python コードです。自分で書くこともできましたが、すでにあなたのために書かれています。あなたは初心者なので、なぜこれらのライブラリのいずれかを使用せず、代わりに独自の最悪のコードを作成しないのかわかりません。ネットワーク IO を正しく設定するのは困難です。

于 2009-01-28T11:19:49.437 に答える
3

質問の意味がよくわかりませんがclose()、接続を閉じたくない場合は電話しないでください...

于 2009-01-28T11:08:09.147 に答える
0

TCP 接続を開いたままにし、使い慣れたプロトコルを使用するクライアントの例については、telnetlib モジュールのソースを参照してください。(申し訳ありませんが、他の誰かがスレッドに関する質問に答える必要があります。)

TCP 接続を開いたままにするサーバーの例は、SocketServer モジュールのソースにあります(標準の Python インストールにはソースが含まれています)。

于 2009-01-28T11:20:54.427 に答える