5

質問があります。Pythonを使用して、一定時間(たとえば、1分)バイトの連続ストリームをホストに送信したいと思います。

これまでの私のコードは次のとおりです。

#! /usr/bin/env python                                                          

import socket
import thread
import time

IP = "192.168.0.2"
PADDING = "a" * 1000 #assume the MTU is slighly above 1000
DATA = PADDING + "this is sentence number = "
PORT = 14444
killed = False
test_time = 60 #60 seconds of testing

def send_data():
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect((IP, PORT))
  count = 1
  starttime = time.clock()
  while elapsed < test_time:
    sent = s.send(DATA + str(count) + "\n")
    if sent == 0: break # assume that if nothing is sent -> connection died
    count = count+1
    elapsed = time.clock() - starttime
    if killed:
      break
  s.close()
  print str(count) + " has been sent"

print "to quit type quit"
thread.start_new_thread(send_data, ())

while True:
  var = raw_input("Enter something: ")
  if var == "quit":
    killed = True

いくつかの質問ですが、毎回time.clockをポーリングする以外に、60秒後にスレッドを停止させるためのより良い方法はありますか?このプログラムを実行すると、バイトは正しく送信されますが、quitと入力すると、var killed = Trueを設定しても、他のスレッドは停止しません。なんでなんだろう?var Killedのスコープは他のスレッドに到達するはずですよね?

ありがとう

4

7 に答える 7

5

threading モジュールの使用をお勧めします。さらに利点は、スレッドを終了するために InterruptableThread を使用することです。スレッドを終了するためにフラグを使用する必要はありませんが、親からこのスレッドで terminate() を呼び出すと例外が発生します。例外を処理できるかどうか。

import threading, ctypes

class InterruptableThread(threading.Thread):
@classmethod
def _async_raise(cls, tid, excobj):
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(excobj))
    if res == 0:
        raise ValueError("nonexistent thread id")
    elif res > 1:
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
        raise SystemError("PyThreadState_SetAsyncExc failed")

def raise_exc(self, excobj):
    assert self.isAlive(), "thread must be started"
    for tid, tobj in threading._active.items():
        if tobj is self:
            self._async_raise(tid, excobj)
            return

def terminate(self):
    self.raise_exc(SystemExit)

編集: 1分待ってから他のスレッドを強制終了する別のスレッドを使用して、このようにコードを書き直すことができます

def send_data:
    IP = ...
    # other vars

    ...
    s = socket.socket(.....)

    # no killed checking
    # no time checking
    # just do your work here
    ...
    s.close()


my_thread = InterruptableThread(target=send_data)
my_thread.start()

def one_minute_kill(who):
   time.sleep(60)
   who.terminate()

killer_thread = InterruptableThread(target=one_minute_kill, args=[my_thread])
killer.start()

print "to quit type quit"
while my_thread.isAlive():
  if raw_input("Enter something: ") == "quit":
    my_thread.terminate()
于 2009-03-03T10:20:58.130 に答える
2

「thread」モジュールでこれを行う方法はわかりませんが、「threading」モジュールで行うことができます。このコードはあなたが望むものを達成すると思います。

threading モジュールのドキュメント: http://docs.python.org/library/threading.html

#!/usr/bin/python

import time
from threading import Thread
import threading
import sys

test_time = 10
killed = False

class SillyThread( threading.Thread ):
    def run(self):
        global killed
        starttime = time.time()
        counter = 0
        while (time.time() - starttime) < test_time:
            if killed:
                break
            counter = counter + 1
            time.sleep(0.1)
        print "I did %d loops" % counter

class ManageThread( threading.Thread ):
    def run(self):
        global killed
        while True:
            var = raw_input("Enter something: ")
            if var == "quit":
                killed = True
                break
        print "Got var [%s]" % var

silly = SillyThread()
silly.start()
ManageThread().start()
Thread.join(silly)
print "bye bye"
sys.exit(0)

time.clock() の代わりに time.time() を使用していることに注意してください。time.clock() は、Unix で経過したプロセッサー時間を提供します ( http://docs.python.org/library/time.htmlを参照)。time.clock() はどこでも動作するはずです。1 分間我慢できないので、test_time を 10 秒に設定します。

10 秒間完全に実行させると、次のようになります。

leif@peacock:~/tmp$ ./test.py
Enter something: I did 100 loops
bye bye

「quit」と入力すると、次のようになります。

leif@peacock:~/tmp$ ./test.py
Enter something: quit
Got var [quit]
I did 10 loops
bye bye

お役に立てれば。

于 2009-03-03T05:48:02.203 に答える
1

前述のように、threadingモジュールを使用すると、はるかに使いやすく、いくつかの同期プリミティブが提供されます。また、指定した時間後に実行されるTimerクラスも提供します。

プログラムを終了させたい場合は、送信スレッドをデーモンにするだけです。これを行うには、start() を呼び出す前に setDaemon(True) を呼び出します (2.6 では代わりにデーモン属性を使用する場合があります)。非デーモン スレッドが実行されている限り、Python は終了しません。

于 2009-03-03T06:11:08.777 に答える
1

これは、スレッドなしで非常に簡単に実行できます。たとえば、Twisted を使用すると、時限呼び出しとプロデューサーをセットアップするだけです。

from twisted.internet.protocol import ClientFactory, Protocol
from twisted.internet import reactor

class Noisy(Protocol):
    def __init__(self, delay, data):
        self.delay = delay
        self.data = data

    def stop(self):
        self.transport.unregisterProducer()
        self.transport.loseConnection()
        reactor.stop()

    def resumeProducing(self):
        self.transport.write(self.data)

    def connectionMade(self):
        self.transport.registerProducer(self, False)
        reactor.callLater(self.delay, self.stop)

factory = ClientFactory()
factory.protocol = lambda: Noisy(60, "hello server")
reactor.connectTCP(host, port, factory)
reactor.run()

これには、スレッド化されたアプローチに比べてさまざまな利点があります。デーモン スレッドに依存しないため、プラットフォームに依存して破棄するのではなく、実際にネットワーク接続をクリーンアップできます (たとえば、必要に応じてクローズ メッセージを送信するなど)。実際のすべての低レベルのネットワーク コードを処理します (元の例では、socket.send が 0 を返す場合に間違ったことを行っています。このコードはそのケースを適切に処理します)。また、別のスレッドで例外を発生させるために ctypes やあいまいな CPython API に依存する必要もありません (そのため、より多くのバージョンの Python に移植でき、他の提案されたアプローチとは異なり、ブロックされた送信を実際にすぐに中断できます)。

于 2009-11-14T02:05:32.617 に答える
0

「終了」が正しく機能していることを確認し、入力が機能していることをテストするために小さな印刷を追加します。

if var == "quit":
 print "Hey we got quit"
于 2009-03-03T03:43:47.370 に答える
0

変数経過は初期化されていません。while ループの上でゼロに設定します。

于 2009-03-03T04:11:21.093 に答える