python基础-线程创建方式
如何用python创建线程
python中提供了两种创建线程的方式
1.采用thread.start_new_thread(funciton,args..)
2.继承threading.Thread类
1.采用thread.start_new_thread(function,agrs..)方式
该方法的使用方式在官方手册中介绍的非常清楚
thread.start_new_thread(function, args[, kwargs])
Start a new thread and return its identifier. The thread executes the function function with the argument list args (which must be a tuple). The optional kwargs argument specifies a dictionary of keyword arguments. When the function returns, the thread silently exits. When the function terminates with an unhandled exception, a stack trace is printed and then the thread exits (but other threads continue to run).
来看一个例子
import thread as t import time #Define a function for the thread def print_time(threadName,delay): count=0; while count<5: time.sleep(delay) count+=1 print "%s(%s): %s " %(threadName,count,time.ctime(time.time())) #Create two threads as follows try: t.start_new_thread(print_time,("thread-1",2)) t.start_new_thread(print_time,("thread-2",3)) except: print "Error:unable to start thread" while 1: pass
2继承threading.Thread
thread是底层模板,threading模块对thread进行了封装。threading操作对线程操作进行了对象化,创建了Thread模块。
实现步骤如下
- 申明一个Thread类的子类
- 覆盖_init_(slef,agrs)方法来增加额外的参数
- 实现线程逻辑
import threading import time exitFlag=0 class myThread(threading.Thread): #implement thead def __init__(self,threadID,name,delay): threading.Thread.__init__(self) self.threadID=threadID self.name=name self.delay=delay def run(self): print "Starting "+ self.name print_time(self.name,self.delay,5) print "Exiting "+ self.name def print_time(threadName,delay,counter): while counter: if exitFlag: thread.exit() # 怎么引用当前的参数 time.sleep(delay) print ("%s(%s): %s"%(threadName,counter,time.ctime(time.time()))) counter -=1; #Create new threads thread1 = myThread(1,"Thread-1",1) thread2 = myThread(2,"Thread-2",3) #start thread1.start() thread2.start()#run和start不同,run直接调用了是 while thread2.isAlive(): if not thread1.isAlive(): exitFlag = 1 print "thread1 is over" pass print "Exiting Main Thread"
线程同步
如果涉及到多个线程对共享资源的访问时,就会出现线程不安全的情况,对于共享数据的抢占可能会导致结果不可预期的情况处理
import threading import time counter = 0 class MyThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): global counter time.sleep(1); counter += 1 print "I am %s, set counter:%s" % (self.name, counter) if __name__ == "__main__": for i in range(0, 200): my_thread = MyThread() my_thread.start()
运行结果部分如下,结果基本上没有什么规律
I am Thread-9,counter:==2==I am Thread-3,counter:==1==I am Thread-6,counter:==3==I am Thread-15,counter:==4==
threading.Lock
对于这种情况有一种方式就是采用互斥锁,设置一个全局互斥锁变量mutext = threading.Lock,在使用公共变量之前抢占互斥锁(mutex.acquire()),在使用完公共变量之后释放互斥锁定(mutex.release())
import threading import time counter = 0 mutex = threading.Lock() class MyThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): global counter, mutex time.sleep(1); if mutex.acquire(): counter += 1 print "I am %s, counter:%s" % (self.name, counter) mutex.release() if __name__ == "__main__": for i in range(0, 100): my_thread = MyThread() my_thread.start()
这样一个线程获取到Lock的时候,这把锁就会进入Locked状态。其他线程就无法再获取,进入到block阻塞状态。
只有当前线程release这把锁的时候,这把锁重新进入到released状态。线程调度会随机挑选一个block的线程获得这把锁,重新进入running状态。
简单的互斥锁还存在一些死锁的问题,后续再讨论。
队列Queue
以上可以看到当多个线程需要共享资源或者数据的时候,会使得线程的使用变得复杂。线程有很多种方式来实现同步如条件变量,事件,锁。但是最佳实践是使用队列,队列使用更加简单,因为能够有效控制单个线程对资源的访问使得线程编程更加安全,而且实现的代码可读性更强。
一个使用队列控制资源的例子如下:
import threading import time import Queue import urllib2 hosts = ['http://www.baidu.com','http://www.sina.com.cn', 'http://www.sohu.com','http://www.asiainfo.com', 'http://www.taobao.com','http://www.126.com' ] queue= Queue.Queue() #populate queue with data for host in hosts: queue.put(host) print host print queue #def Thread class class QueueHandler(threading.Thread): def __init__(self,queue): threading.Thread.__init__(self) self.queue = queue def run(self): while True: host = self.queue.get() url = urllib2.urlopen(host) print 'thread is %s, visiting %s ,and the content======= %s'%(self.getName(),host,url.read(10)) self.queue.task_done() start = time.time() print start # loading thread def main(): for i in range(5): t= QueueHandler(queue) t.setDaemon(True) t.start() main() #block the program queue.join() print ('time used:%s'%(time.time()-start))