Python多线程编程

来源:互联网 发布:html编程有什么作用 编辑:程序博客网 时间:2024/03/29 17:46

Python多线程学习

 一、Python中的线程使用:

    Python中使用线程有两种方式:函数或者用类来包装线程对象。

1、  函数式:调用thread模块中的start_new_thread()函数来产生新线程。如下例:

import timeimport threaddef timer(no, interval):    cnt = 0    while cnt<10:        print 'Thread:(%d) Time:%s/n'%(no, time.ctime())        time.sleep(interval)        cnt+=1    thread.exit_thread()    def test(): #Use thread.start_new_thread() to create 2 new threads    thread.start_new_thread(timer, (1,1))    thread.start_new_thread(timer, (2,2)) if __name__=='__main__':    test()


    上面的例子定义了一个线程函数timer,它打印出10条时间记录后退出,每次打印的间隔由interval参数决定。thread.start_new_thread(function, args[, kwargs])的第一个参数是线程函数(本例中的timer方法),第二个参数是传递给线程函数的参数,它必须是tuple类型,kwargs是可选参数。

    线程的结束可以等待线程自然结束,也可以在线程函数中调用thread.exit()或thread.exit_thread()方法。

2、  创建threading.Thread的子类来包装一个线程对象,如下例:

import threadingimport timeclass timer(threading.Thread): #The timer class is derived from the class threading.Thread    def __init__(self, num, interval):        threading.Thread.__init__(self)        self.thread_num = num        self.interval = interval        self.thread_stop = False     def run(self): #Overwrite run() method, put what you want the thread do here        while not self.thread_stop:            print 'Thread Object(%d), Time:%s/n' %(self.thread_num, time.ctime())            time.sleep(self.interval)    def stop(self):        self.thread_stop = True        def test():    thread1 = timer(1, 1)    thread2 = timer(2, 2)    thread1.start()    thread2.start()    time.sleep(10)    thread1.stop()    thread2.stop()    return if __name__ == '__main__':    test()

   

    就我个人而言,比较喜欢第二种方式,即创建自己的线程类,必要时重写threading.Thread类的方法,线程的控制可以由自己定制。

threading.Thread类的使用:

1,在自己的线程类的__init__里调用threading.Thread.__init__(self, name = threadname)

Threadname为线程的名字

2, run(),通常需要重写,编写代码实现做需要的功能。

3,getName(),获得线程对象名称

4,setName(),设置线程对象名称

5,start(),启动线程

6,jion([timeout]),等待另一线程结束后再运行。

7,setDaemon(bool),设置子线程是否随主线程一起结束,必须在start()之前调用。默认为False。

8,isDaemon(),判断线程是否随主线程一起结束。

9,isAlive(),检查线程是否在运行中。

    此外threading模块本身也提供了很多方法和其他的类,可以帮助我们更好的使用和管理线程。可以参看http://www.python.org/doc/2.5.2/lib/module-threading.html。


假设两个线程对象t1和t2都要对num=0进行增1运算,t1和t2都各对num修改10次,num的最终的结果应该为20。但是由于是多线程访问,有可能出现下面情况:在num=0时,t1取得num=0。系统此时把t1调度为”sleeping”状态,把t2转换为”running”状态,t2页获得num=0。然后t2对得到的值进行加1并赋给num,使得num=1。然后系统又把t2调度为”sleeping”,把t1转为”running”。线程t1又把它之前得到的0加1后赋值给num。这样,明明t1和t2都完成了1次加1工作,但结果仍然是num=1。

    上面的case描述了多线程情况下最常见的问题之一:数据共享。当多个线程都要去修改某一个共享数据的时候,我们需要对数据访问进行同步。

1、  简单的同步

最简单的同步机制就是“锁”。锁对象由threading.RLock类创建。线程可以使用锁的acquire()方法获得锁,这样锁就进入“locked”状态。每次只有一个线程可以获得锁。如果当另一个线程试图获得这个锁的时候,就会被系统变为“blocked”状态,直到那个拥有锁的线程调用锁的release()方法来释放锁,这样锁就会进入“unlocked”状态。“blocked”状态的线程就会收到一个通知,并有权利获得锁。如果多个线程处于“blocked”状态,所有线程都会先解除“blocked”状态,然后系统选择一个线程来获得锁,其他的线程继续沉默(“blocked”)。

Python中的thread模块和Lock对象是Python提供的低级线程控制工具,使用起来非常简单。如下例所示:

import threadimport timemylock = thread.allocate_lock()  #Allocate a locknum=0  #Shared resourcedef add_num(name):    global num    while True:        mylock.acquire() #Get the lock         # Do something to the shared resource        print 'Thread %s locked! num=%s'%(name,str(num))        if num >= 5:            print 'Thread %s released! num=%s'%(name,str(num))            mylock.release()            thread.exit_thread()        num+=1        print 'Thread %s released! num=%s'%(name,str(num))        mylock.release()  #Release the lock.def test():    thread.start_new_thread(add_num, ('A',))    thread.start_new_thread(add_num, ('B',))if __name__== '__main__':    test()


Python 在thread的基础上还提供了一个高级的线程控制库,就是之前提到过的threading。Python的threading module是在建立在thread module基础之上的一个module,在threading module中,暴露了许多thread module中的属性。在thread module中,python提供了用户级的线程同步工具“Lock”对象。而在threading module中,python又提供了Lock对象的变种: RLock对象。RLock对象内部维护着一个Lock对象,它是一种可重入的对象。对于Lock对象而言,如果一个线程连续两次进行acquire操作,那么由于第一次acquire之后没有release,第二次acquire将挂起线程。这会导致Lock对象永远不会release,使得线程死锁。RLock对象允许一个线程多次对其进行acquire操作,因为在其内部通过一个counter变量维护着线程acquire的次数。而且每一次的acquire操作必须有一个release操作与之对应,在所有的release操作完成之后,别的线程才能申请该RLock对象。

下面来看看如何使用threading的RLock对象实现同步。

 

import threadingmylock = threading.RLock()num=0 class myThread(threading.Thread):    def __init__(self, name):        threading.Thread.__init__(self)        self.t_name = name            def run(self):        global num        while True:            mylock.acquire()            print '/nThread(%s) locked, Number: %d'%(self.t_name, num)            if num>=4:                mylock.release()                print '/nThread(%s) released, Number: %d'%(self.t_name, num)                break            num+=1            print '/nThread(%s) released, Number: %d'%(self.t_name, num)            mylock.release()            def test():    thread1 = myThread('A')    thread2 = myThread('B')    thread1.start()    thread2.start() if __name__== '__main__':    test()

我们把修改共享数据的代码成为“临界区”。必须将所有“临界区”都封闭在同一个锁对象的acquire和release之间。

2、  条件同步

锁只能提供最基本的同步。假如只在发生某些事件时才访问一个“临界区”,这时需要使用条件变量Condition。

Condition对象是对Lock对象的包装,在创建Condition对象时,其构造函数需要一个Lock对象作为参数,如果没有这个Lock对象参数,Condition将在内部自行创建一个Rlock对象。在Condition对象上,当然也可以调用acquire和release操作,因为内部的Lock对象本身就支持这些操作。但是Condition的价值在于其提供的wait和notify的语义。

条件变量是如何工作的呢?首先一个线程成功获得一个条件变量后,调用此条件变量的wait()方法会导致这个线程释放这个锁,并进入“blocked”状态,直到另一个线程调用同一个条件变量的notify()方法来唤醒那个进入“blocked”状态的线程。如果调用这个条件变量的notifyAll()方法的话就会唤醒所有的在等待的线程。

如果程序或者线程永远处于“blocked”状态的话,就会发生死锁。所以如果使用了锁、条件变量等同步机制的话,一定要注意仔细检查,防止死锁情况的发生。对于可能产生异常的临界区要使用异常处理机制中的finally子句来保证释放锁。等待一个条件变量的线程必须用notify()方法显式的唤醒,否则就永远沉默。保证每一个wait()方法调用都有一个相对应的notify()调用,当然也可以调用notifyAll()方法以防万一。


生产者与消费者问题是典型的同步问题。这里简单介绍两种不同的实现方法。

1,  条件变量

 

import threadingimport timeclass Producer(threading.Thread):    def __init__(self, t_name):        threading.Thread.__init__(self, name=t_name)     def run(self):        global x        con.acquire()        if x > 0:            con.wait()        else:            for i in range(5):                x=x+1                print "producing..." + str(x)            con.notify()        print x        con.release() class Consumer(threading.Thread):    def __init__(self, t_name):        threading.Thread.__init__(self, name=t_name)    def run(self):        global x        con.acquire()        if x == 0:            print 'consumer wait1'            con.wait()        else:            for i in range(5):                x=x-1                print "consuming..." + str(x)            con.notify()        print x        con.release() con = threading.Condition()x=0print 'start consumer'c=Consumer('consumer')print 'start producer'p=Producer('producer') p.start()c.start()p.join()c.join()print x

 

    上面的例子中,在初始状态下,Consumer处于wait状态,Producer连续生产(对x执行增1操作)5次后,notify正在等待的Consumer。Consumer被唤醒开始消费(对x执行减1操作) 

2,  同步队列

Python中的Queue对象也提供了对线程同步的支持。使用Queue对象可以实现多个生产者和多个消费者形成的FIFO的队列。

生产者将数据依次存入队列,消费者依次从队列中取出数据。

# producer_consumer_queuefrom Queue import Queueimport randomimport threadingimport time #Producer threadclass Producer(threading.Thread):    def __init__(self, t_name, queue):        threading.Thread.__init__(self, name=t_name)        self.data=queue    def run(self):        for i in range(5):            print "%s: %s is producing %d to the queue!/n" %(time.ctime(), self.getName(), i)            self.data.put(i)            time.sleep(random.randrange(10)/5)        print "%s: %s finished!" %(time.ctime(), self.getName()) #Consumer threadclass Consumer(threading.Thread):    def __init__(self, t_name, queue):        threading.Thread.__init__(self, name=t_name)        self.data=queue    def run(self):        for i in range(5):            val = self.data.get()            print "%s: %s is consuming. %d in the queue is consumed!/n" %(time.ctime(), self.getName(), val)            time.sleep(random.randrange(10))        print "%s: %s finished!" %(time.ctime(), self.getName()) #Main threaddef main():    queue = Queue()    producer = Producer('Pro.', queue)    consumer = Consumer('Con.', queue)    producer.start()    consumer.start()    producer.join()    consumer.join()    print 'All threads terminate!' if __name__ == '__main__':    main()


在上面的例子中,Producer在随机的时间内生产一个“产品”,放入队列中。Consumer发现队列中有了“产品”,就去消费它。本例中,由于Producer生产的速度快于Consumer消费的速度,所以往往Producer生产好几个“产品”后,Consumer才消费一个产品。

Queue模块实现了一个支持多producer和多consumer的FIFO队列。当共享信息需要安全的在多线程之间交换时,Queue非常有用。Queue的默认长度是无限的,但是可以设置其构造函数的maxsize参数来设定其长度。Queue的put方法在队尾插入,该方法的原型是:

put( item[, block[, timeout]])

如果可选参数block为true并且timeout为None(缺省值),线程被block,直到队列空出一个数据单元。如果timeout大于0,在timeout的时间内,仍然没有可用的数据单元,Full exception被抛出。反之,如果block参数为false(忽略timeout参数),item被立即加入到空闲数据单元中,如果没有空闲数据单元,Full exception被抛出。

Queue的get方法是从队首取数据,其参数和put方法一样。如果block参数为true且timeout为None(缺省值),线程被block,直到队列中有数据。如果timeout大于0,在timeout时间内,仍然没有可取数据,Empty exception被抛出。反之,如果block参数为false(忽略timeout参数),队列中的数据被立即取出。如果此时没有可取数据,Empty exception也会被抛出。

======================

我们在做软件开发的时候很多要用到多线程技术。例如如果做一个下载软件象flashget就要用到、象在线视频工具realplayer也 要用到因为要同时下载media stream还要播放。其实例子是很多的。

线程相对进程来说是“轻量级”的,操作系统用较少的资源创建和管理线程。程序中的线程在相同的内存空间中执行,并共享许多相同的资源。

python 中如何创建一个线程对象

如果你要创建一个线程对象,很简单,只要你的类继承threading.Thread , 然后在__init__ 里首先调用threading.Thread 的__init__ 方法即可

import threading
class mythread(threading.Thread):
def __init__(self, threadname):
threading.Thread.__init__(self, name = threadname)

….

这才仅仅是个空线程,我可不是要他拉空车的,他可得给我干点实在活。很简单,重写类的run() 方法即可,把你要在线程执行时做的事情都放到里面

import threading
import time
class mythread(threading.Thread):
def __init__(…):
….
def run(self):
for i in range(10):
print self.getName, i
time.sleep(1)

以上代码我们让这个线程在执行之后每隔1秒输出一次信息到屏幕,10次后结束

getName() 是threading.Thread 类的一个方法,用来获得这个线程对 象的name 。还有一个方法setName() 当然就是来设置这个线程对象的name 的了。

如果要创建一个线程,首先就要先创建一个线程对象

mythread1 = mythread(’mythread 1′)

一个线程对象被创建后,他就处于“born ”(诞 生状态)

如何让这个线程对象开始运行呢?只要调用线程对象的start() 方 法即可

mythread1.start()

现在线程就处于“ready ”状态或者也称为“runnable ”状态。

奇怪吗?不是已经start 了吗?为什么不称为“running ”状态呢?其实是有原因的。因为我们的计算机一般是 不具有真正并行处理能力的。我们所谓的多线程只是把时间分成片段,然后隔一个时间段就让一个线程执行一下,然后进入“sleeping ”状态,然后唤醒另一个在“sleeping ”的线程,如此循环runnable->sleeping->runnable… ,只是因为计算机执行速度很快,而时间片段间隔很小,我们感受不到,以为是同时进行的。所以说一个线程在start 了之后只是处在了可以运行的状态,他什么时候运行还是由系统来进行调度的。

那一个线程什么时候会“dead ”呢?一般来说当 线程对象的run 方法执行结束或者在执行中抛出异常的 话,那么这个线程就会结束了。系统会自动对“dead ” 状态线程进行清理。

如果一个线程t1 在执行的过程中需要等待另一个线 程t2 执行结束后才能运行的话那就可以在t1 在调用t2 的join() 方 法

….
def t1(…):

t2.join()

这样t1 在执行到t2.join() 语句后就会等待t2 结束后才会继续运行。

但是假如t1 是个死循环的话那么等待就没有意义 了,那怎么办呢?可以在调用t2 的join() 方法的时候给一个浮点数做超时参数,这样这个线程就不会 等到花儿也谢了了。我等你10s,你不回来我还不允许我改嫁啊? :)

def t1(…):

t2.join(10)

 

############自己加的备注###############

在结合线程和队列使用的情况中,除了使用threading.Thread的join()以外,还可以选择使用Queue.Queue的join()方法。前者代表等待该线程结束,后者代表等待该队列中所有的元素被处理完毕。

需要注意的是,如果使用队列中的join()方法时,一定要记得在每次线程处理结束的时候调用task_done()方法。

下面贴一段PYTHON手册上的内容:

 

Queue. task_done ( )

Indicate that a formerly enqueued task is complete. Used by queue consumer threads. For each get() used to fetch a task, a subsequent call to task_done()tells the queue that the processing on the task is complete.

If a join() is currently blocking, it will resume when all items have been processed (meaning that a task_done() call was received for every item that had beenput() into the queue).

Raises a ValueError if called more times than there were items placed in the queue.

New in version 2.5.

Queue. join ( )

Blocks until all items in the queue have been gotten and processed.

The count of unfinished tasks goes up whenever an item is added to the queue. The count goes down whenever a consumer thread calls task_done() to indicate that the item was retrieved and all work on it is complete. When the count of unfinished tasks drops to zero, join() unblocks.

New in version 2.5.

###########################


如果一个进程的主线程运行完毕而子线程还在执行的话,那么进程就不会退出,直到所有子线程结束为止,如何让主线程结束的时候其他子线程也乖乖的跟老 大撤退呢?那就要把那些不听话的人设置为听话的小弟,使用线程对象的setDaemon() 方 法,参数为bool 型。True 的话就代表你要听话,我老大(主线程)扯呼,你也要跟着撤, 不能拖后腿。如果是False 的话就不用那么听话了,老 大允许你们将在外军命有所不受的。需要注意的是setDaemon() 方 法必须在线程对象没有调用start() 方法之前调用, 否则没效果。

t1 = mythread(’t1′)
print t1.getName(),t1.isDaemon()
t1.setDaemon(True)
print t1.getName(),t1.isDaemon()
t1.start()
print ‘main thread exit’

当执行到 print ‘main thread exit’ 后, 主线程就退出了,当然t1 这个线程也跟着结束了。但是如 果不使用t1 线程对象的setDaemon() 方法的话,即便主线程结束了,还要等待t1线 程自己结束才能退出进程。isDaemon() 是用来获 得一个线程对象的Daemonflag 状态的。

如何来获得与线程有关的信息呢?

获得当前正在运行的线程的引用

running = threading.currentThread()

获得当前所有活动对象(即run 方法开始但是未终 止的任何线程)的一个列表

threadlist = threading.enumerate()

获得这个列表的长度

threadcount = threading.activeCount()

查看一个线程对象的状态调用这个线程对象的isAlive() 方 法,返回1代表处于“runnable ”状态且没有“dead ”

threadflag = threading.isAlive()

Python线程编程(二)简单的线程同步

多个执行线程经常要共享数据,如果仅仅读取共享数据还好,但是如果多个线程要修改共享数据的话就可能出现无法预料的结果。

假如两个线程对象t1 和t2 都要对数值num=0 进行增1运算,那么t1 和t2 都各对num 修改10 次的话,那么num 最 终的结果应该为20 。但是如果当t1 取得num 的值时(假如此时num 为0 ),系统把t1 调度为“sleeping ” 状态,而此时t2 转换为“running ”状态,此时t2 获得的num 的 值也为0 ,然后他把num+1 的值1 赋给num 。 系统又把t2 转化为“sleeping ”状态,t1 为“running ” 状态,由于t1 已经得到num 值为0 ,所以他也把num+1 的 值赋给了num 为1 。本来是2 次增1 运 行,结果却是num 只增了1 次。类似这样的情况在多线程同时执行的时候是有可能发生的。所以为 了防止这类情况的出现就要使用线程同步机制。

最简单的同步机制就是“锁”

锁对象用threading.RLock 类创建

mylock = threading.RLock()

如何使用锁来同步线程呢?线程可以使用锁的acquire() (获得)方法,这样锁就进入“locked ”状态。每 次只有一个线程可以获得锁。如果当另一个线程试图获得这个锁的时候,就会被系统变为“blocked ”状态,直到那个拥有锁的线程调用锁的release() (释放)方法,这样锁就会进入“unlocked ”状态。“blocked ” 状态的线程就会收到一个通知,并有权利获得锁。如果多个线程处于“blocked ” 状态,所有线程都会先解除“blocked ”状态,然后 系统选择一个线程来获得锁,其他的线程继续沉默(“blocked ”)。

import threading
mylock = threading.RLock()
class mythread(threading.Thread)

def run(self …):
…     #此处 不可以 放置修改共享数据的代码
mylock.acquire()
…     #此处 可以 放置修改共享数据的代码
mylock.release()
… 
#此处 不可以 放置修改共享数据的代码

我们把修改共享数据的代码称为“临界区”,必须将所有“临界区”都封闭在同一锁对象的acquire() 和release() 方 法调用之间。

锁只能提供最基本的同步级别。有时需要更复杂的线程同步,例如只在发生某些事件时才访问一个临界区(例如当某个数值改变时)。这就要使用“条件变 量”。

条件变量用threading.Condition 类 创建

mycondition = threading.Condition()

条件变量是如何工作的呢?首先一个线程成功获得一个条件变量后,调用此条件变量的wait() 方法会导致这个线程释放这个锁,并进入“blocked ”状态,直到另一个线程调用同一个条件变量的notify() 方法来唤醒那个进入“blocked ”状态的线程。如果调用这个条件变量的notifyAll() 方法的话就会唤醒所有的在等待的线程。

如果程序或者线程永远处于“blocked ”状态 的话,就会发生死锁。所以如果使用了锁、条件变量等同步机制的话,一定要注意仔细检查,防止死锁情况的发生。对于可能产生异常的临界区要使用异常处理机制 中的finally 子句来保证释放锁。等待一个条件变量 的线程必须用notify() 方法显式的唤醒,否则就永 远沉默。保证每一个wait() 方法调用都有一个相对应 的notify() 调用,当然也可以调用notifyAll() 方法以防万一。

Python线程编程(三)同步队列

我 们经常会采用生产者/消费者关系的两个线程来处理一个共享缓冲区的数据。例如一个生产者线程接受用户数据放入一个共享缓冲区里,等待一个消费者线程对数据 取出处理。但是如果缓冲区的太小而生产者和消费者两个异步线程的速度不同时,容易出现一个线程等待另一个情况。为了尽可能的缩短共享资源并以相同速度工作 的各线程的等待时间,我们可以使用一个“队列”来提供额外的缓冲区。

创建一个“队列”对象

import Queue
myqueue = Queue.Queue(maxsize = 10)
 Queue.Queue 类 即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue 的 构造函数的可选参数maxsize 来设定队列长度。如果maxsize 小于1 就表示队列长度无限。

 

将一个值放入队列中

myqueue.put(10)

调 用队列对象的put() 方法在队尾插入一个项目。put() 有两个参数,第一个item 为必需的,为插入项目的值;第二个block 为可选参数,默认为1 。如果队列当前为空且block 为1 ,put() 方法就使调用线程暂停,直到空出一个数据单元。如果block 为0 ,put 方 法将引发Full 异常。

将一个值从队列中取出

myqueue.get()

调用 队列对象的get() 方法从队头删除并返回一个项目。可 选参数为block ,默认为1 。如果队列为空且block 为1 ,get() 就使调用线程暂停,直至有项目可用。如果block为0,队列将引发Empty 异常。

我们用一个例子来展示如何使用Queue # queue_example.py
from Queue import Queue
import threading
import random
import time

 

# Producer thread
class Producer(threading.Thread):
def __init__(self, threadname, queue):
threading.Thread.__init__(self, name = threadname)
self.sharedata = queue
def run(self):
for i in range(20):
print self.getName(),’adding’,i,’to queue’
self.sharedata.put(i)
time.sleep(random.randrange(10)/10.0)
print self.getName(),’Finished’

# Consumer thread
class Consumer(threading.Thread):
def __init__(self, threadname, queue):
threading.Thread.__init__(self, name = threadname)
self.sharedata = queue
def run(self):
for i in range(20):
print self.getName(),’got a value:’,self.sharedata.get()
time.sleep(random.randrange(10)/10.0)
print self.getName(),’Finished’

# Main thread
def main():
queue = Queue()
producer = Producer(’Producer’, queue)
consumer = Consumer(’Consumer’, queue)

print ‘Starting threads …’
producer.start()
consumer.start()

producer.join()
consumer.join()

print ‘All threads have terminated.’

if __name__ == ‘__main__’:
main()

示例代码中实现了两个类:生产者类Producer 和 消费者类Consumer 。前者在一个随机的时间内放入 一个值到队列queue 中然后显示出来,后者在一定随机 的时间内从队列queue 中取出一个值并显示出来。


本文转自:http://crazier9527.javaeye.com/blog/442100


python中的多线程编程(一)
    -------python核心编程学习
1. 多线程的作用
简而言之,多线程是并行处理相互独立的子任务,从而大幅度提高整个任务的效率。

2. Python中的多线程模块
Python中提供几个用于多线程编程的模块,包括thread,threading和Queue等

thread模块提供了基本的线程和锁的支持,除产生线程外,也提供基本的同步数据结构锁对象,其中包括:
start_new_thread(function, args kwargs=None)  产生一个新的线程来运行给定函数
allocate_lock()  分配一个LockType类型的锁对象
exit() 让线程退出
acquire(wait=None) 尝试获取锁对象
locked()  如果获取了锁对象返回TRUE,否则返回FALSE
release()  释放锁

threading提供了更高级别,功能更强的线程管理功能
Thread类 表示一个线程的执行的对象
Lock 锁原语对象
RLock 可重入锁对象,使单线程可以再次获得已经获取锁

queue模块允许用户创建一个可以用于多个线程之间共享数据的队列数据结构
可用于进程间的通讯,让各个线程之间共享数据
模块函数queue(size)  创建一个大小为size的Queue对象
queue对象函数 qsize()  返回队列大小
                empty()  队列为空返回True,否则返回False
                       put(item, block=0)  把ITEM放到队列中,block不为0,函数会一直阻塞到队列中
                get(block=0) 从队列中取一个对象,若果给block,函数会一直阻塞到队列中有对象为止

====================

一)线程基础

1、创建线程:

thread模块提供了start_new_thread函数,用以创建线程。start_new_thread函数成功创建后还可以对其进行操作。

其函数原型:

    start_new_thread(function,atgs[,kwargs])

其参数含义如下:

    function: 在线程中执行的函数名

    args:元组形式的参数列表。

    kwargs: 可选参数,以字典的形式指定参数

方法一:通过使用thread模块中的函数创建新线程。

[python] view plaincopy
  1. >>> import thread  
  2. >>> def run(n):  
  3.     for i in range(n):  
  4.         print i  
  5.   
  6.           
  7. >>> thread.start_new_thread(run,(4,))   #注意第二个参数一定要是元组的形式  
  8. 53840  
  9.   
  10.   
  11. 1  
  12. >>>   
  13. 2  
  14. 3  
  15. KeyboardInterrupt  
  16. >>> thread.start_new_thread(run,(2,))  
  17. 17840  
  18.   
  19.   
  20. 1  
  21. >>>   
  22. thread.start_new_thread(run,(),{'n':4})  
  23. 39720  
  24.   
  25.   
  26. 1  
  27. >>>   
  28. 2  
  29. 3  
  30. thread.start_new_thread(run,(),{'n':3})  
  31. 32480  
  32.   
  33.   
  34. 1  
  35. >>>   
  36. 2  

方法二:通过继承threading.Thread创建线程

[python] view plaincopy
  1. >>> import threading  
  2. >>> class mythread(threading.Thread):  
  3.     def __init__(self,num):  
  4.         threading.Thread.__init__(self)  
  5.         self.num = num  
  6.     def run(self):               #重载run方法  
  7.         print 'I am'self.num  
  8.   
  9.           
  10. >>> t1 = mythread(1)  
  11. >>> t2 = mythread(2)  
  12. >>> t3 = mythread(3)  
  13. >>> t1.start()           #运行线程t1  
  14. I am  
  15. >>>  1  
  16. t2.start()  
  17. I am  
  18. >>>  2  
  19. t3.start()  
  20. I am  
  21. >>>  3  

方法三:使用threading.Thread直接在线程中运行函数。

[python] view plaincopy
  1. import threading  
  2. >>> def run(x,y):  
  3.     for i in range(x,y):  
  4.         print i  
  5.   
  6. >>> t1 = threading.Thread(target=run,args=(15,20)) #直接使用Thread附加函数args为函数参数  
  7.   
  8. >>> t1.start()  
  9. 15  
  10. >>>   
  11. 16  
  12. 17  
  13. 18  
  14. 19  

 

二)Thread对象中的常用方法:

1、isAlive方法:

[python] view plaincopy
  1. >>> import threading  
  2. >>> import time  
  3. >>> class mythread(threading.Thread):  
  4.     def __init__(self,id):  
  5.         threading.Thread.__init__(self)  
  6.         self.id = id  
  7.     def run(self):  
  8.         time.sleep(5)    #休眠5秒  
  9.         print self.id  
  10.   
  11.           
  12. >>> t = mythread(1)  
  13. >>> def func():  
  14.     t.start()  
  15.     print t.isAlive()    #打印线程状态  
  16.   
  17.       
  18. >>> func()  
  19. True  
  20. >>> 1  

2、join方法:

原型:join([timeout]) 

    timeout: 可选参数,线程运行的最长时间

[python] view plaincopy
  1. import threading  
  2. >>> import time     #导入time模块  
  3. >>> class Mythread(threading.Thread):  
  4.     def __init__(self,id):  
  5.         threading.Thread.__init__(self)  
  6.         self.id = id  
  7.     def run(self):  
  8.         x = 0  
  9.         time.sleep(20)  
  10.         print self.id  
  11.   
  12.           
  13. >>> def func():  
  14.     t.start()  
  15.     for i in range(5):  
  16.         print i  
  17.   
  18.           
  19. >>> t = Mythread(2)  
  20. >>> func()  
  21. 0  
  22. 1  
  23. 2  
  24. 3  
  25. 4  
  26. >>> 2  
  27. def func():  
  28.     t.start()  
  29.     t.join()  
  30.     for i in range(5):  
  31.         print i  
  32.   
  33.           
  34. >>> t = Mythread(3)  
  35. >>> func()  
  36. 3  
  37. 0  
  38. 1  
  39. 2  
  40. 3  
  41. 4  
  42. >>>   

 

3、线程名:

[python] view plaincopy
  1. >>> import threading  
  2. >>> class mythread(threading.Thread):  
  3.     def __init__(self,threadname):  
  4.         threading.Thread.__init__(self,name=threadname)  
  5.     def run(self):  
  6.         print self.getName()  
  7.   
  8.           
  9. >>>   
  10. >>> t1 = mythread('t1')  
  11. >>> t1.start()  
  12. t1  
  13. >>>   

 4、setDaemon方法

在脚本运行的过程中有一个主线程,如果主线程又创建了一个子线程,那么当主线程退出时,会检验子线程是否完成。如果子线程未完成,则主线程会在等待子线程完成后退出。

当需要主线程退出时,不管子线程是否完成都随主线程退出,则可以使用Thread对象的setDaemon方法来设置。

 

三)线程同步

1.简单的线程同步

使用Thread对象的Lock和RLock可以实现简单的线程同步。对于如果需要每次只有一个线程操作的数据,可以将操作过程放在acquire方法和release方法之间。如:

 

[python] view plaincopy
  1. # -*- coding:utf-8 -*-  
  2. import threading  
  3. import time  
  4. class mythread(threading.Thread):  
  5.     def __init__(self,threadname):  
  6.         threading.Thread.__init__(self,name = threadname)  
  7.     def run(self):  
  8.         global x                #设置全局变量  
  9. #       lock.acquire()          #调用lock的acquire方法  
  10.         for i in range(3):  
  11.             x = x + 1  
  12.         time.sleep(2)  
  13.         print x  
  14. #       lock.release()          #调用lock的release方法  
  15. #lock = threading.RLock()        #生成Rlock对象  
  16. t1 = []  
  17. for i in range(10):  
  18.     t = mythread(str(i))  
  19.     t1.append(t)  
  20. x = 0                   #将全局变量的值设为0  
  21. for i in t1:   
  22.     i.start()  
  23.   
  24. E:/study/python/workspace>xianchengtongbu.py  
  25. 3  
  26. 6  
  27. 9  
  28. 12  
  29. 15  
  30. 18  
  31. 21  
  32. 24  
  33. 27  
  34. 30  

如果将lock.acquire()和lock.release(),lock = threading.Lock()删除后保存运行脚本,结果将是输出10个30。30是x的最终值,由于x是全局变量,每个线程对其操作后进入休眠状态,在线程休眠的时候,python解释器就执行了其他的线程而是x的值增加。当所有线程休眠结束后,x的值已被所有线修改为了30,因此输出全部为30。

 

2、使用条件变量保持线程同步。

Python的Condition对象提供了对复制线程同步的支持。使用Condition对象可以在某些事件触发后才处理数据。Condition对象除了具有acquire方法和release的方法外,还有wait方法、notify方法、notifyAll方法等用于条件处理。

[python] view plaincopy
  1. # -*- coding:utf-8 -*-  
  2. import threading  
  3. class Producer(threading.Thread):  
  4.     def __init__(self,threadname):  
  5.         threading.Thread.__init__(self,name = threadname)  
  6.     def run(self):  
  7.         global x  
  8.         con.acquire()  
  9.         if x == 1000000:  
  10.             con.wait()  
  11.         #   pass  
  12.         else:  
  13.             for i in range(1000000):  
  14.                 x = x + 1  
  15.             con.notify()  
  16.         print x  
  17.         con.release()  
  18. class Consumer(threading.Thread):  
  19.     def __init__(self,threadname):  
  20.         threading.Thread.__init__(self,name = threadname)  
  21.     def run(self):  
  22.         global x   
  23.         con.acquire()  
  24.         if x == 0:  
  25.             con.wait()  
  26.             #pass  
  27.         else:  
  28.             for i in range(1000000):  
  29.                 x = x - 1  
  30.             con.notify()  
  31.         print x   
  32.         con.release()  
  33. con = threading.Condition()  
  34. x = 0  
  35. p = Producer('Producer')  
  36. c = Consumer('Consumer')  
  37. p.start()  
  38. c.start()  
  39. p.join()  
  40. c.join()  
  41. print x  
  42.   
  43. E:/study/python/workspace>xianchengtongbu2.py  
  44. 1000000  
  45. 0  
  46. 0  

线程间通信:

Event对象用于线程间的相互通信。他提供了设置信号、清除信宏、等待等用于实现线程间的通信。

1、设置信号。Event对象使用了set()方法后,isSet()方法返回真。

2、清除信号。使用Event对象的clear()方法后,isSet()方法返回为假。

3、等待。当Event对象的内部信号标志为假时,则wait()方法一直等到其为真时才返回。还可以向wait传递参数,设定最长的等待时间。

[python] view plaincopy
  1. # -*- coding:utf-8 -*-  
  2. import threading  
  3. class mythread(threading.Thread):  
  4.     def __init__(self,threadname):  
  5.         threading.Thread.__init__(self,name = threadname)  
  6.     def run(self):  
  7.         global event  
  8.         if event.isSet():  
  9.             event.clear()  
  10.             event.wait()   #当event被标记时才返回  
  11.             print self.getName()  
  12.         else:  
  13.             print self.getName()  
  14.             event.set()  
  15. event = threading.Event()  
  16. event.set()  
  17. t1 = []  
  18. for i in range(10):  
  19.     t = mythread(str(i))  
  20.     t1.append(t)  
  21. for i in t1:  
  22.     i.start()  



原创粉丝点击