2009-03-03 11 views
5

मेरे पास एक प्रश्न है। मैं पाइथन का उपयोग करके कुछ समय के लिए कुछ होस्ट के लिए बाइट की निरंतर धाराएं भेजना चाहता हूं (चलो 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 

कुछ सवाल है, वहाँ 60 सेकंड मतदान के अलावा अन्य time.clock हर बार के बाद एक धागा मरने जाने के लिए एक बेहतर तरीका है? जब मैं इस प्रोग्राम को चलाता हूं, तो यह बाइट्स को सही तरीके से भेजता है, लेकिन जब मैंने टाइप किया तो दूसरा थ्रेड मर जाएगा, भले ही मैं var kill = True सेट करता हूं। मुझे आश्चर्य है कि वह क्यों है? var Killed का दायरा अन्य धागे सही तक पहुंच जाना चाहिए?

धन्यवाद

+0

क्या कोई होस्ट वास्तव में उस पते पर मौजूद है? क्या आप आउटपुट या किसी अन्य प्रोग्राम को कैप्चर करने के लिए नेटकैट का उपयोग कर रहे हैं? – johnny

+0

मुझे लगता है कि 'मारे गए' का दायरा ठीक है। – Jiri

उत्तर

0

कि सुनिश्चित करें "छोड़" सही ढंग से काम कर रहा है और परीक्षण करने के लिए है कि इनपुट काम कर रहा है एक छोटे प्रिंट जोड़ें।

if var == "quit": 
print "Hey we got quit" 
0

वैरिएबल समाप्त हो गया है प्रारंभ नहीं किया गया है। इसे लूप के ऊपर शून्य पर सेट करें।

2

मुझे नहीं पता कि "थ्रेड" मॉड्यूल के साथ ऐसा कैसे करें, लेकिन मैं इसे "थ्रेडिंग" मॉड्यूल के साथ कर सकता हूं। मुझे लगता है कि यह कोड आप जो चाहते हैं उसे पूरा करता है।

सूत्रण मॉड्यूल पर दस्तावेज़ीकरण के लिए: 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() यूनिक्स पर विलुप्त प्रोसेसर समय देता है (देखें http://docs.python.org/library/time.html)। मुझे लगता है कि time.clock() हर जगह काम करना चाहिए। मैंने अपना test_time 10 सेकंड में सेट किया क्योंकि मेरे पास एक मिनट के लिए धैर्य नहीं है।

[email protected]:~/tmp$ ./test.py 
Enter something: I did 100 loops 
bye bye 

यह इस प्रकार होता अगर मैं टाइप 'छोड़' बताया गया है::

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

आशा इस मदद करता है

यहाँ अगर मैं इसे पूर्ण 10 सेकंड चलाते हैं क्या होता है।

1

जैसा ऊपर बताया गया है, threading मॉड्यूल का उपयोग करें, इसका उपयोग करना बहुत आसान है और कई सिंक्रनाइज़ेशन प्राइमेटिव प्रदान करता है। यह एक Timer कक्षा भी प्रदान करता है जो निर्दिष्ट समय के बाद चलता है।

यदि आप सिर्फ प्रोग्राम से बाहर निकलना चाहते हैं, तो आप बस भेजने वाले थ्रेड को डिमन बना सकते हैं। आप प्रारंभ() (कॉल करने के बजाय एक डेमन विशेषता का उपयोग कर सकते हैं) से पहले setDaemon (True) को कॉल करके ऐसा करते हैं। पाइथन इतनी देर से बाहर नहीं निकलेगा क्योंकि एक गैर-डिमन थ्रेड चल रहा है।

5

मैंने थ्रेडिंग मॉड्यूल का उपयोग करने की सिफारिश की। थ्रेड को समाप्त करने के लिए इंटरप्टेबल थ्रेड का उपयोग करने के लिए और भी अधिक लाभ है। आपको अपने थ्रेड को समाप्त करने के लिए ध्वज का उपयोग करने की आवश्यकता नहीं है लेकिन अपवाद तब होगा जब आप इस थ्रेड पर पैरेंट() को पैरेंट से कॉल करते हैं। आप अपवाद संभाल सकते हैं या नहीं।

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() 
+1

ध्यान दें कि इस कोड को 64-बिट सिस्टम (64-बिट लिनक्स, वैसे भी) के तहत काम करने के लिए प्राप्त करने के लिए आपको 'ctypes.c_long' पर कॉल में 'PyThreadState_SetAsyncExc' का पहला पैरामीटर लपेटना होगा। अन्यथा यह 32-बिट पूर्णांक के रूप में पारित हो जाता है, जो अतिप्रवाह होता है, और आपको "nonexistent थ्रेड आईडी" ValueError अपवाद मिलता है। – intuited

0

यह killed के दायरे परीक्षण करने के लिए आसान है:

>>> import thread 
>>> killed = False 
>>> import time 
>>> def test(): 
... while True: 
... time.sleep(1) 
... if killed: 
...  print 'Dead.' 
...  break 
... 
>>> thread.start_new_thread(test,()) 
25479680 
>>> time.sleep(3) 
>>> killed = True 
>>> Dead. 
1

आप थ्रेड के बिना इसे आसानी से कर सकते हैं। पिरोया दृष्टिकोण से अधिक विभिन्न लाभों

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 के मामले में गलत चीज़ कर रहा है; यह कोड उस मामले को ठीक से संभाल देगा)। आपको किसी अन्य धागे में अपवाद बढ़ाने के लिए सीटीपीएस या अस्पष्ट सीपीथन एपीआई पर भरोसा नहीं करना पड़ता है (इसलिए यह पाइथन के अधिक संस्करणों के लिए पोर्टेबल है और वास्तव में कुछ अन्य सुझाए गए दृष्टिकोणों के विपरीत, अवरुद्ध प्रेषण को तुरंत बाधित कर सकता है)।

संबंधित मुद्दे