阿小信大人的头像
Where there is a Python, there is a way. 阿小信大人

Python线程笔记整理2014-09-02 05:21

创建线程

import threading
import time

def clock(interval):
    while True:
        print("the time is %s"%time.ctime())
        time.sleep(interval)


t = threading.Thread(target=clock, args=(15, ))
t.daemon = True
t.start()

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

class ClockThread(threading.Thread):
    def __init__(self, interval):
        threading.Thread.__init__(self)
        self.demon = True
        self.interval = interval

    def run(self):
        while True:
            print("the time is %s"%time.ctime())
            time.sleep(interval)

t = ClockThread(15)
t.start()

实例t支持的方法和属性:

Thread(group=None, target=None, name=None, args=(), kwargs={}) Thread对象原型

t.start() 启动线程

t.run() 线程启动时调用此方法

t.join([timeout]) 等待直到线程终止或者超时

t.is_alive() 线程活动bool值

t.name 线程名称

t.ident 线程标识符

t.daemon 线程后台标志bool值

Timer对象

Timer(interval, func [, arg [, kwargs]]) 在稍后某个时间执行某个函数

实例支持的方法:

t.start() 启动定时器

t.cancel() 如果函数尚未执行取消定时器

线程同步

使用Thread对象的Lock和RLock可以实现简单的线程同步。

Lock对象和RLock对象都具有acquire方法和release方法。对于如果需要每次只有一个线程操作的数据,可以将操作过程放在acquire方法和release方法之间。

import threading 
import time

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

    def run(self):  
        global x     
        lock.acquire()          
        for i in range(3):
            x = x + 1
        time.sleep(1)    
        print x
        lock.release()

lock = threading.RLock()   
tl = []     
for i in range(5):
    t = mythread(str(i))   
    tl.append(t)

x=0              
for i in tl:
    i.start()

输出:

3
6
9
12
15

如果不lock则输出:

30
30
30
30
30

修改后的脚本输出都是30也就是i的最终值。由于i是全局变量,在每个线程对i进行操作后就“休眠”了。在线程休眠的时候,Python解释器已经执行了其他的线程,而使i值增加。当所有线程“休眠”结束后,i的值已被所有线程修改变成了30,因此输出为30。

而在使用Lock对象的脚本中,对全局变量i的操作放在acquire方法和release方法之间。Python解释器每次仅允许一个线程对i进行操作。只有当该线程操作完后,并且结束休眠以后才开始下一个线程,所以使用Lock对象的脚本输出是依次递增的。

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

Python 的Condition对象提供了对复杂线程同步的支持。使用Condition对象可以在某些事件触发后才处理数据。Condition对象除了具有acquire方法和release方法以外,还有wait方法、notify方法、notifyAll方法等用于条件处理。以下P_C.py脚本使用Condition对象来实现著名的生产者和消费者的关系。

import threading

class Producer(threading.Thread): 
    def _init_(self,threadname):
        threading.Thread._init_(self,name = threadname)
    def run(self):
        global x
        con.acquire() 
        if x == 1000000:
            con.wait() 
            pass
        else:
            for i in range(1000000):
                x = x + 1
            con.notify() 
        print x
        con.release()

class Consumer(threading.Thread): 
    def _init_(self,threadname):
        threading.Thread._init_(self,name = threadname)

    def run(self):
        global x
        con.acquire()
        if x == 0:
            con.wait()
            pass
        else:
            for i in range(1000000):
                x = x - 1
            con.notify()
        print x
        con.release()

con = threading.Condition() 
x=0
p = Producer('Producer')  
c = Consumer('Consumer') 
p.start() 
c.start()
p.join() 
c.join()
print x

输出:

1000000
0
0

删除Condition()输出:

932546
-143430
-143430

使用队列保持线程同步

Python 中的Queue对象也提供了对线程同步的支持。使用Queue对象可以实现多生产者和多消费者形成的先进先出的队列。每个生产者将数据依次存入队列,而每个消费者则依次从队列中取出数据。以下MP_MC.py脚本使用Queue对象实现多个生产者和消费者的关系。

import threading
import time 
import Queue

class Producer(threading.Thread):
    def _init_(self,threadname):
        threading.Thread._init_(self,name = threadname)

    def run(self):
        global queue
        queue.put(self.getName())
        print self.getName(),'put ',self.getName(),' to queue'

class Consumer(threading.Thread):
    def _init_(self,threadname):
        threading.Thread._init_(self,name = threadname)

    def run(self):
        global queue
        print self.getName(),'get ',queue.get(),'from queue'
queue = Queue.Queue()
plist = []
clist = [] 
for i in range(10):
    p = Producer('Producer' + str(i))
    plist.append(p)
for i in range(10):
    c = Consumer('Consumer' + str(i))
    clist.append(c)
for i in plist:
    i.start() 
    i.join()
for i in clist:
    i.start()   
    i.join()

输出:

Producer0 put Producer0 to queue
Producer1 put Producer1 to queue
Producer2 put Producer2 to queue
Producer3 put Producer3 to queue
Producer4 put Producer4 to queue
Producer5 put Producer5 to queue
Producer6 put Producer6 to queue
Producer7 put Producer7 to queue
Producer8 put Producer8 to queue
Producer9 put Producer9 to queue
Consumer0 get Producer0 from queue
Consumer1 get Producer1 from queue
Consumer2 get Producer2 from queue
Consumer3 get Producer3 from queue
Consumer4 get Producer4 from queue
Consumer5 get Producer5 from queue
Consumer6 get Producer6 from queue
Consumer7 get Producer7 from queue
Consumer8 get Producer8 from queue
Consumer9 get Producer9 from queue

线程间的通信

Event 对象实现了简单的线程通信机制,它提供了设置信号、清除信号、等待等用于实现线程间的通信。

1 设置信号

使用Event对象的set()方法可以设置Event对象内部的信号标志为真。Event对象提供了isSet()方法来判断其内部信号标志的状态。当使用Event对象的set()方法后,isSet()方法返回真。

2 清除信号

使用Event对象的clear()方法可以清除Event对象内部的信号标志,即将其设置为假。当使用Event对象的clear()方法后,isSet()方法返回假。

3 等待

Event 对象wait的wait方法只有在其内部信号为真时才会很快地执行完成并返回。当Event对象的内部信号标志为假时,则wait方法一直等到其为真时才返回。另外还可以向wait方法传递参数,以设定最长等待时间。

使用 Event 对象实现线程间通信

配合使用Event对象的几种方法可以实现进程间的简单通信。以下的event.py脚本即使用Event对象实现进程间的通信。

import threading                                        #  导入 threading 模块
class mythread(threading.Thread):
    def _init_(self,threadname):
        threading.Thread._init_(self,name = threadname)
    def run(self):
        global event                                  #  使用全局 Event 对象
        if event.isSet():                             #  判断 Event 对象内部信号标志
            event.clear()                              #  若已设置标志则清除
            event.wait()                               #  调用 wait 方法
            print self.getName()
        else:
            print self.getName()
            event.set()                            #  设置 Event 对象内部信号标志
event = threading.Event()                           #  生成 Event 对象
event.set()                                         #  设置 Event 对象内部信号标志
tl = []
for i in range(10):
    t = mythread(str(i))
    tl.append(t)                                     #  生成线程列表

for i in tl:
    i.start()                                            #  运行线程

输出

1
0
3
5
4
7
2
6
9

如果您觉得从我的分享中得到了帮助,并且希望我的博客持续发展下去,请点击支付宝捐赠,谢谢!

若非特别声明,文章均为阿小信的个人笔记,转载请注明出处。文章如有侵权内容,请联系我,我会及时删除。

#Python#  
分享到:
阅读[1251] 评论[0]

上一篇:迷宫题
下一篇:PyInstall用法

你可能也感兴趣的文章推荐

本文最近访客

发表评论