import threading import time count = 1 class KissThread(threading.Thread): def run(self): global count print "%s # %s: Pretending to do stuff" % (self.name, count) time.sleep(2) print "done with stuff # %s" % self.name if __name__ == '__main__': for i in range(5): KissThread().start()
这里可以看出threading.Thread()实例有两个方法,一个start(),一个run(),其中,start()方法启动一个新线程。这个新线程运行线程的run()方法。threading.Thread()实例的start()方法,相当于是vfork(),然后执行clone()出来的threading.Thread().run()。
这个例子本来是抄书上的,但是发现有问题,因为并发、多线程编程时,必需要考虑“同步”问题。比如上面的例子,本意是按顺序输出count的值,但实际上,有可能会输出相同的count值:
$ python threading_test.py
Thread-1 # 1: Pretending to do stuff
Thread-2 # 2: Pretending to do stuff
Thread-3 # 2: Pretending to do stuff
Thread-4 # 4: Pretending to do stuff
Thread-5 # 5: Pretending to do stuff
Thread-1 done with stuff
Thread-3 done with stuff
Thread-2 done with stuff
Thread-4 done with stuff
Thread-5 done with stuff
即,并发、多线程运行的代码,运行顺序不可预测。即threading.Thread().run()中的代码行的执行顺序,不可预测。所以count的值,并不像想象中的按顺序输出。
但是,线程可以共享数据,比较全局变量。这样“进程间通信”问题变得容易了。但是因此而带的问题,需要特别注意,否则程序往往是错的。
from threading import Thread from Queue import Queue import subprocess import sys def pinger(i, queue): while True: ip = queue.get() print "Thread %s: Pinging %s" % (i, ip) ret = subprocess.call("ping -c2 -w2 %s" % ip, shell=True, stdout=open('/dev/null','w'), stderr=subprocess.STDOUT) if ret == 0: print "%s : is alive" % ip else: print "%s : did not respond" % ip queue.task_done() if __name__ == '__main__': queue = Queue() for i in range(5): worker = Thread(target=pinger, args=(i,queue)) worker.setDaemon(True) worker.start() for i in open(sys.argv[1], 'r'): queue.put(i.strip()) print "Main Thread Waiting" queue.join() print "Done"
1. 线程实例化时的两个常用参数:
target,函数对象,注意是函数对象,是函数名pinger,不是运行函数pinger(),是线程start()之后,运行的代码。
args,参数元组,target实例化(函数实例化,就是运行函数)时传递给target的参数。target需要两个变量。通常第二个变量是队列。
见Thread类的定义:
__init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None)
run()/target的定义:
def run(self): try: if self.__target: self.__target(*self.__args, **self.__kwargs) finally: # Avoid a refcycle if the thread is running a function with # an argument that has a member that points to the thread. del self.__target, self.__args, self.__kwargs
2. queue=Queue()
queue.task_done()类似于队列计数减1,queue.join()类似于“当队列计数为0时,返回;并不断检查、重试”。
转载请注明:爱开源 » Python线程样例