python 线程理解
2017-09-26 19:41
288 查看
和 java 一样,线程的理解相对于进程而言,区别就是线程是共享 状态,资源和内存,属于轻量级的,方便,但是也带来了死锁,争用条件和高复杂性在内的各种问题。
python线程的创建:import threading t = threading.Thread(target='方法名',args=('元祖参数信息',))
有关 Thread()参数为:
def__init__(self, group=None, target=None, name=None, args=(), kwargs={})
参数group是预留的,用于将来扩展;
参数target是一个可调用对象(也称为活动[activity]),在线程启动后执行;
参数name是线程的名字。默认值为“Thread-N“,N是一个数字。
参数args和kwargs分别表示调用target时的参数列表和关键字参数。
t.start() 开始运行
t.setDaemon() setDaemon(True)将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。子线程启动后,父线程也继续执行下去,当父线程执行完最后一条语句print "all over %s" %ctime()后,没有等待子线程,直接就退出了,同时子线程也一同结束。
创建 Thread 继承类:
class MyThread(threading.Thread()): 注意里边必须有run() 方法 这里才是执行的核心,同时需要在外部调用该对象的 start 方法来让线程得到执行。
Thread方法说明
t.start() : 激活线程,
t.getName() : 获取线程的名称
t.setName() : 设置线程的名称
t.name : 获取或设置线程的名称
t.is_alive() : 判断线程是否为激活状态
t.isAlive() :判断线程是否为激活状态
t.setDaemon() 设置为后台线程或前台线程(默认:False);通过一个布尔值设置线程是否为守护线程,必须在执行start()方法之后才可以使用。如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止;如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
t.isDaemon() : 判断是否为守护线程
t.ident :获取线程的标识符。线程标识符是一个非零整数,只有在调用了start()方法之后该属性才有效,否则它只返回None。
t.join() :逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
t.run() :线程被cpu调度后自动执行线程对象的run方法
import datetime,threading
from time import sleep
class MyThread(threading.Thread):
def run(self):
print('%s says at time = %s' %(self.getName(),datetime.datetime.now()))
sleep(3)
for t in range(2):
t = MyThread()
t.start()
t.join() #这里的join是让子线程得到完全的执行后才执行父线程 不然父执行完,子没得执行了
print('end time = %s' %datetime.datetime.now())
Thread类还定义了以下常用方法与属性:
Thread.getName()
Thread.setName()
Thread.name
用于获取和设置线程的名称。
Thread.ident
获取线程的标识符。线程标识符是一个非零整数,只有在调用了start()方法之后该属性才有效,否则它只返回None。
Thread.is_alive()
Thread.isAlive()
判断线程是否是激活的(alive)。从调用start()方法启动线程,到run()方法执行完毕或遇到未处理异常而中断 这段时间内,线程是激活的。
Thread.join([timeout])
调用Thread.join将会使主调线程堵塞,直到被调用线程运行结束或超时。参数timeout是一个数值类型,表示超时时间,如果未提供该参数,那么主调线程将一直堵塞到被调线程结束。
join()
保持阻塞状态,直到处理了队列中的所有项目为止。在将一个项目添加到该队列时,未完成的任务的总数就会增加。当使用者线程调用 task_done() 以表示检索了该项目、并完成了所有的工作时,那么未完成的任务的总数就会减少。当未完成的任务的总数减少到零时,join() 就会结束阻塞状态。
下面是一个封装线程的例子:
from time import ctime,sleep
import threading
class MyThread(threading.Thread):
def __init__(self,func,args={}):
print('开始初始化 线程对象,使用的方法名为: %s 参数为: %s' %(func,args))
threading.Thread.__init__(self)
self.func = func
self.args = args
def run(self):
threads = []
for m,k in self.args.items():
t = threading.Thread(target=self.func,args=(m,k))
threads.append(t)
print('一共需要的线程分发数量: %s 开始执行线程.....' %(len(threads)))
for t in threads:
t.setDaemon(True)
t.start()
for t in threads:
t.join() #这里保证子进程的完全执行
list_data = {'热血高校.mp4':2,'舞动青春.mp3':5}
def testThread(name,time):
for m in range(2): ##每个线程都自动分发两条
print('start play is name = %s sleep = %s nowtime = %s' %(name,time,ctime()))
sleep(time)
m = MyThread(testThread,list_data)
m.start() # 调用start 开始执行我的线程
print('all is over %s ' %ctime())
下面不得不谈一谈有关锁的问题,由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,CPU接着执行其他线程。为了保证数据的准确性,引入了锁的概念。所以,可能出现如下问题:
例:假设列表A的所有元素就为0,当一个线程从前向后打印列表的所有元素,另外一个线程则从后向前修改列表的元素为1,那么输出的时候,列表的元素就会一部分为0,一部分为1,这就导致了数据的不一致。锁的出现解决了这个问题。
例如未加锁前:
import threading
import time
globals_num = 0 # 公共资源
def Func():
global globals_num
globals_num += 1
time.sleep(1) # 因为这里每次都睡1秒,实际执行的时候根本等不到这里执行完就开始下一条线程
print(globals_num) # 最后的结果就是这里始终打印 10 因为第10此线程结束后才开始子线程的sleep
for i in range(10):
t = threading.Thread(target=Func)
t.start() #这样会导致每次新的线程持有资源时的资源信息都不一样 即每次都+1
结果 10 10 10 10 10 10 10 10 10 10
加锁后:
import threading
import time
globals_num = 0
lock = threading.RLock()
def Func():
lock.acquire() #获得锁
global globals_num
globals_num += 1
time.sleep(1)
print(globals_num)
lock.release() #释放锁
threads = []
for i in range(10):
t = threading.Thread(target=Func)
threads.append(t)
t.start() ## 题外话 本来这里加上 t.join() 也能得到效果,但是意义不一样,因为那样的话就实际上属于单线程了,注意 join 不能与 start 在循环里连用。
结果 1 2 3 4 5 6 7 8 9 10
顺便谈谈join用法:
错误例子:
threads = [Thread() for i in range(5)]
for thread in threads:
thread.start()
thread.join()
执行过程:
1. 第一次循环中,主线程通过start函数激活线程1,线程1进行计算.
2. 由于start函数不阻塞主线程,在线程1进行运算的同时,主线程向下执行join函数.
3. 执行join之后,主线程被线程1阻塞,在线程1返回结果之前,主线程无法执行下一轮循环.
4. 线程1计算完成之后,解除对主线程的阻塞.
5. 主线程进入下一轮循环,激活线程2并被其阻塞…
如此往复,可以看出,本来应该并发的五个线程,在这里变成了顺序队列,效率和单线程无异.
正确用法:
使用两个循环分别处理start和join函数.即可实现并发.但是注意资源的锁
threads = [Thread() for i in range(5)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
顺便说一句 千万注意锁的全局性,不然就无法生效。即
lock = threading.Lock()
必须全局使用
Python提供的Condition对象提供了对复杂线程同步问题的支持。Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。线程首先acquire一个条件变量,然后判断一些条件。如果条件不满足则wait;如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件。不断的重复这一过程,从而解决复杂的同步问题。相当于 锁和 event的联合使用。
在典型的设计风格里,利用condition变量用锁去通许访问一些共享状态,线程在获取到它想得到的状态前,会反复调用wait()。修改状态的线程在他们状态改变时调用 notify() or notify_all(),用这种方式,线程会尽可能的获取到想要的一个等待者状态。 例子: 生产者-消费者模型,
Lock是threading模块提供的锁对象,Lock默认创建的是一个锁对象,当我们需要对全局对象进行操作的时候,可以通过Lock创建对象来锁定对象,Lock对象就好比java中的synchronize(aObject)代码中的aObject对象。
而condition除了具有Lock对象的acquire方法和release方法外,还有wait、notify、notifyAll方法等用于条件处理。Condition对象可以在某些事件触发或者达到特定条件后才处理数据。很像java中锁一个对象后,对象调用notify或者notifyAll方法去触发操作。Condition还支持从外界引用一个Lock对象。
再谈谈 threading.RLock和threading.Lock 的区别
RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。 如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。
有关 threading.Event
python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。
事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
clear:将“Flag”设置为False
set:将“Flag”设置为True
Event.isSet() :判断标识位是否为Ture。
有关队列的用法:
import queue
q = queue.Queue(maxsize=0) # 构造一个先进显出队列,maxsize指定队列长度,为0 时,表示队列长度无限制。
q.join() # 等到队列为kong的时候,在执行别的操作
q.qsize() # 返回队列的大小 (不可靠)
q.empty() # 当队列为空的时候,返回True 否则返回False (不可靠)
q.full() # 当队列满的时候,返回True,否则返回False (不可靠)
q.put(item, block=True, timeout=None) # 将item放入Queue尾部,item必须存在,可以参数block默认为True,表示当队列满时,会等待队列给出可用位置,
为False时为非阻塞,此时如果队列已满,会引发queue.Full 异常。 可选参数timeout,表示 会阻塞设置的时间,过后,
如果队列无法给出放入item的位置,则引发 queue.Full 异常
q.get(block=True, timeout=None) # 移除并返回队列头部的一个值,可选参数block默认为True,表示获取值的时候,如果队列为空,则阻塞,为False时,不阻塞,
若此时队列为空,则引发 queue.Empty异常。 可选参数timeout,表示会阻塞设置的时候,过后,如果队列为空,则引发Empty异常。
q.put_nowait(item) # 等效于 put(item,block=False)
q.get_nowait() # 等效于 get(item,block=False)
我的线程池创建,不知道对不对,暂时贴上吧
借用网上一个例子:
python线程的创建:import threading t = threading.Thread(target='方法名',args=('元祖参数信息',))
有关 Thread()参数为:
def__init__(self, group=None, target=None, name=None, args=(), kwargs={})
参数group是预留的,用于将来扩展;
参数target是一个可调用对象(也称为活动[activity]),在线程启动后执行;
参数name是线程的名字。默认值为“Thread-N“,N是一个数字。
参数args和kwargs分别表示调用target时的参数列表和关键字参数。
t.start() 开始运行
t.setDaemon() setDaemon(True)将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。子线程启动后,父线程也继续执行下去,当父线程执行完最后一条语句print "all over %s" %ctime()后,没有等待子线程,直接就退出了,同时子线程也一同结束。
创建 Thread 继承类:
class MyThread(threading.Thread()): 注意里边必须有run() 方法 这里才是执行的核心,同时需要在外部调用该对象的 start 方法来让线程得到执行。
Thread方法说明
t.start() : 激活线程,
t.getName() : 获取线程的名称
t.setName() : 设置线程的名称
t.name : 获取或设置线程的名称
t.is_alive() : 判断线程是否为激活状态
t.isAlive() :判断线程是否为激活状态
t.setDaemon() 设置为后台线程或前台线程(默认:False);通过一个布尔值设置线程是否为守护线程,必须在执行start()方法之后才可以使用。如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止;如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
t.isDaemon() : 判断是否为守护线程
t.ident :获取线程的标识符。线程标识符是一个非零整数,只有在调用了start()方法之后该属性才有效,否则它只返回None。
t.join() :逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
t.run() :线程被cpu调度后自动执行线程对象的run方法
import datetime,threading
from time import sleep
class MyThread(threading.Thread):
def run(self):
print('%s says at time = %s' %(self.getName(),datetime.datetime.now()))
sleep(3)
for t in range(2):
t = MyThread()
t.start()
t.join() #这里的join是让子线程得到完全的执行后才执行父线程 不然父执行完,子没得执行了
print('end time = %s' %datetime.datetime.now())
Thread类还定义了以下常用方法与属性:
Thread.getName()
Thread.setName()
Thread.name
用于获取和设置线程的名称。
Thread.ident
获取线程的标识符。线程标识符是一个非零整数,只有在调用了start()方法之后该属性才有效,否则它只返回None。
Thread.is_alive()
Thread.isAlive()
判断线程是否是激活的(alive)。从调用start()方法启动线程,到run()方法执行完毕或遇到未处理异常而中断 这段时间内,线程是激活的。
Thread.join([timeout])
调用Thread.join将会使主调线程堵塞,直到被调用线程运行结束或超时。参数timeout是一个数值类型,表示超时时间,如果未提供该参数,那么主调线程将一直堵塞到被调线程结束。
join()
保持阻塞状态,直到处理了队列中的所有项目为止。在将一个项目添加到该队列时,未完成的任务的总数就会增加。当使用者线程调用 task_done() 以表示检索了该项目、并完成了所有的工作时,那么未完成的任务的总数就会减少。当未完成的任务的总数减少到零时,join() 就会结束阻塞状态。
下面是一个封装线程的例子:
from time import ctime,sleep
import threading
class MyThread(threading.Thread):
def __init__(self,func,args={}):
print('开始初始化 线程对象,使用的方法名为: %s 参数为: %s' %(func,args))
threading.Thread.__init__(self)
self.func = func
self.args = args
def run(self):
threads = []
for m,k in self.args.items():
t = threading.Thread(target=self.func,args=(m,k))
threads.append(t)
print('一共需要的线程分发数量: %s 开始执行线程.....' %(len(threads)))
for t in threads:
t.setDaemon(True)
t.start()
for t in threads:
t.join() #这里保证子进程的完全执行
list_data = {'热血高校.mp4':2,'舞动青春.mp3':5}
def testThread(name,time):
for m in range(2): ##每个线程都自动分发两条
print('start play is name = %s sleep = %s nowtime = %s' %(name,time,ctime()))
sleep(time)
m = MyThread(testThread,list_data)
m.start() # 调用start 开始执行我的线程
print('all is over %s ' %ctime())
下面不得不谈一谈有关锁的问题,由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,CPU接着执行其他线程。为了保证数据的准确性,引入了锁的概念。所以,可能出现如下问题:
例:假设列表A的所有元素就为0,当一个线程从前向后打印列表的所有元素,另外一个线程则从后向前修改列表的元素为1,那么输出的时候,列表的元素就会一部分为0,一部分为1,这就导致了数据的不一致。锁的出现解决了这个问题。
例如未加锁前:
import threading
import time
globals_num = 0 # 公共资源
def Func():
global globals_num
globals_num += 1
time.sleep(1) # 因为这里每次都睡1秒,实际执行的时候根本等不到这里执行完就开始下一条线程
print(globals_num) # 最后的结果就是这里始终打印 10 因为第10此线程结束后才开始子线程的sleep
for i in range(10):
t = threading.Thread(target=Func)
t.start() #这样会导致每次新的线程持有资源时的资源信息都不一样 即每次都+1
结果 10 10 10 10 10 10 10 10 10 10
加锁后:
import threading
import time
globals_num = 0
lock = threading.RLock()
def Func():
lock.acquire() #获得锁
global globals_num
globals_num += 1
time.sleep(1)
print(globals_num)
lock.release() #释放锁
threads = []
for i in range(10):
t = threading.Thread(target=Func)
threads.append(t)
t.start() ## 题外话 本来这里加上 t.join() 也能得到效果,但是意义不一样,因为那样的话就实际上属于单线程了,注意 join 不能与 start 在循环里连用。
结果 1 2 3 4 5 6 7 8 9 10
顺便谈谈join用法:
错误例子:
threads = [Thread() for i in range(5)]
for thread in threads:
thread.start()
thread.join()
执行过程:
1. 第一次循环中,主线程通过start函数激活线程1,线程1进行计算.
2. 由于start函数不阻塞主线程,在线程1进行运算的同时,主线程向下执行join函数.
3. 执行join之后,主线程被线程1阻塞,在线程1返回结果之前,主线程无法执行下一轮循环.
4. 线程1计算完成之后,解除对主线程的阻塞.
5. 主线程进入下一轮循环,激活线程2并被其阻塞…
如此往复,可以看出,本来应该并发的五个线程,在这里变成了顺序队列,效率和单线程无异.
正确用法:
使用两个循环分别处理start和join函数.即可实现并发.但是注意资源的锁
threads = [Thread() for i in range(5)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
顺便说一句 千万注意锁的全局性,不然就无法生效。即
lock = threading.Lock()
必须全局使用
""" threading Condition 例子 """
Python提供的Condition对象提供了对复杂线程同步问题的支持。Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。线程首先acquire一个条件变量,然后判断一些条件。如果条件不满足则wait;如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件。不断的重复这一过程,从而解决复杂的同步问题。相当于 锁和 event的联合使用。
在典型的设计风格里,利用condition变量用锁去通许访问一些共享状态,线程在获取到它想得到的状态前,会反复调用wait()。修改状态的线程在他们状态改变时调用 notify() or notify_all(),用这种方式,线程会尽可能的获取到想要的一个等待者状态。 例子: 生产者-消费者模型,
Lock是threading模块提供的锁对象,Lock默认创建的是一个锁对象,当我们需要对全局对象进行操作的时候,可以通过Lock创建对象来锁定对象,Lock对象就好比java中的synchronize(aObject)代码中的aObject对象。
而condition除了具有Lock对象的acquire方法和release方法外,还有wait、notify、notifyAll方法等用于条件处理。Condition对象可以在某些事件触发或者达到特定条件后才处理数据。很像java中锁一个对象后,对象调用notify或者notifyAll方法去触发操作。Condition还支持从外界引用一个Lock对象。
import threading import time """ 生产者 消费者模式 """ def consumer(cond,name): with cond: print("consumer before wait name = %s and time = %s" %(name,time.ctime())) cond.wait() print("consumer after wait name = %s and time = %s" %(name,time.ctime())) def producer(cond): with cond: print("producer before notifyAll %s " %time.ctime()) cond.notifyAll() #这里唤醒 子线程的阻塞 print("producer after notifyAll %s " %time.ctime()) condition = threading.Condition() c1 = threading.Thread(name="c1", target=consumer, args=(condition,'thread-1')) #创建消费者线程1 condition 传参 c2 = threading.Thread(name="c2", target=consumer, args=(condition,'thread-2')) # 创建消费者线程2 condition 传参 p = threading.Thread(name="p", target=producer, args=(condition,)) #创建生产者线程 codition 传参 c1.start() time.sleep(2) c2.start() time.sleep(2) p.start()
再谈谈 threading.RLock和threading.Lock 的区别
RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。 如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。
有关 threading.Event
python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。
事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
clear:将“Flag”设置为False
set:将“Flag”设置为True
Event.isSet() :判断标识位是否为Ture。
import threading """ 线程 Event 例子 """ def do(event,name): print('start') event.wait() ##这里开始阻塞 print('execute %s' %name) event_obj = threading.Event() # 这里创建 Event 对象 for i in range(10): t = threading.Thread(target=do, args=(event_obj,'任意参')) # 这里将Event 对象作为参数传入线程列表 t.start() #这里的start 只会执行到 方法内 event.wait() 之前,之后的需要再次调用event.set 方法才能执行下去 event_obj.clear() inp = input('input:') if inp == 'true': event_obj.set() """ 线程 定时器的例子 """
from threading import Timer def fun(): print "hello, world" if __name__=='__main__': t = Timer(5.0, fun) t.start() # 开始执行线程,但是不会打印"hello, world" t.cancel() # 因为cancel取消了线程的执行,所以fun()函数不会被执行
有关队列的用法:
import queue
q = queue.Queue(maxsize=0) # 构造一个先进显出队列,maxsize指定队列长度,为0 时,表示队列长度无限制。
q.join() # 等到队列为kong的时候,在执行别的操作
q.qsize() # 返回队列的大小 (不可靠)
q.empty() # 当队列为空的时候,返回True 否则返回False (不可靠)
q.full() # 当队列满的时候,返回True,否则返回False (不可靠)
q.put(item, block=True, timeout=None) # 将item放入Queue尾部,item必须存在,可以参数block默认为True,表示当队列满时,会等待队列给出可用位置,
为False时为非阻塞,此时如果队列已满,会引发queue.Full 异常。 可选参数timeout,表示 会阻塞设置的时间,过后,
如果队列无法给出放入item的位置,则引发 queue.Full 异常
q.get(block=True, timeout=None) # 移除并返回队列头部的一个值,可选参数block默认为True,表示获取值的时候,如果队列为空,则阻塞,为False时,不阻塞,
若此时队列为空,则引发 queue.Empty异常。 可选参数timeout,表示会阻塞设置的时候,过后,如果队列为空,则引发Empty异常。
q.put_nowait(item) # 等效于 put(item,block=False)
q.get_nowait() # 等效于 get(item,block=False)
我的线程池创建,不知道对不对,暂时贴上吧
import threading,queue from time import ctime,sleep """ 线程池 首先要有线程池线程内最高个数 其次 要有队列来存放线程 3 要有对于线程池的个数大小的判断 如果低于一定数量就创建 4 队列本身属于安全 不需要加锁 5 要有一个get 一个set 方法 """ class ThreadPool(): def __init__(self,max_num=10,min_num=3): self.que = queue.Queue(max_num) self.min_num = min_num #开始创建固定线程数 for m in range(max_num): self.que.put(threading.Thread) print('创建出线程队列 个数 %s '%self.que.qsize()) def currentT(self): return self.que.qsize() def getThread(self): current_t = self.currentT() if current_t <self.min_num: print(' 当前线程数: %s 小于规定数:%s 开始增加.....' %(current_t,self.min_num)) self.addThread(3) return self.que.get() def addThread(self): self.que.put(threading.Thread) def addThread(self,num): for m in range(num): self.que.put(threading.Thread) print('新增线程数: %s ' %3) def func(t_name,args): print('%s 你来了,开始玩耍吧 你带来了 %s '%(t_name,args)) if __name__=="__main__": t = ThreadPool() for m in range(20): thread = t.getThread() print('当前线程数量:%s' %t.currentT()) tt = thread(target=func,args=('线程'+str(m),'随便参数')) tt.start()
借用网上一个例子:
#coding:utf-8 #---- Condition #---- 捉迷藏的游戏 import threading, time #找 class Hider(threading.Thread): def __init__(self, cond, name): super(Hider, self).__init__() print('准备去找人....') self.cond = cond self.name = name def run(self): time.sleep(1) #确保先运行Seeker中的方法 print('hider 开始 获取锁...') self.cond.acquire() #b print(self.name + ': 我已经把眼睛蒙上了') print('hander 开始唤醒...') self.cond.notify() print('hander开始等待....') self.cond.wait() #c print(self.name + ': 我找到你了 ~_~') self.cond.notify() self.cond.release() #g print(self.name + ': 我赢了') #h #藏 class Seeker(threading.Thread): def __init__(self, cond, name): super(Seeker, self).__init__() print('准备藏起来.....') self.cond = cond self.name = name def run(self): print('seeker 开始 获取锁...') self.cond.acquire() #获取锁对象 print('seeker 开始等待...') self.cond.wait() #a #释放对琐的占用,同时线程挂起在这里,直到被notify并重新占有琐。 print(self.name + ': 我已经藏好了,你快来找我吧') print('sekker 开始唤醒') self.cond.notify() print('seeker 开始等待') self.cond.wait() #e self.cond.release() print(self.name + ': 被你找到了,哎~~~') cond = threading.Condition() #创建线程控制器 seeker = Seeker(cond, 'seeker') hider = Hider(cond, 'hider') seeker.start() hider.start()
相关文章推荐
- 通过Python脚本理解系统线程 推荐
- 理解 Python 中的线程
- 理解 Python 中的线程
- Python多线程的创建,相关函数和守护线程的理解
- Python的协程,线程,进程的理解及实现
- 通过Python脚本理解系统线程
- 理解 Python 中的线程
- 理解 Python 中的线程
- Python中线程的理解
- Python中理解进程(Process),线程(Thread)和协程(Coroutines)的感悟
- 通过Python脚本理解系统线程
- 通过Python脚本理解系统线程
- 理解 Python 中的线程
- python理解进程、线程和协程
- Python多线程的创建,相关函数和守护线程的理解
- 3个实例帮你理解Python中的线程
- python 进程、线程和协程的理解(转)
- 理解Python并发编程一篇就够了|线程篇
- 树莓派 - 2 Python - b 网络与进程/线程模块:socket, threading, subprocess
- 理解python多线程(python多线程简明教程)