铁乐学python_Day42_线程-信号量事件条件

线程中的信号量

同进程的一样,Semaphore管理一个内置的计数器,

每当调用acquire()时内置计数器-1;调用release() 时内置计数器+1;

计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

实例:(同时只有5个线程可以获得semaphore,即可以限制最大连接数为5):
from threading import Thread,Semaphore
import threading
import time def func():
sm.acquire()
print('%s get sm' %threading.current_thread().getName())
time.sleep(3)
sm.release() if __name__ == '__main__':
sm=Semaphore(5)
for i in range(23):
t=Thread(target=func)
t.start()

与进程池是完全不同的概念,进程池Pool(4),最大只能产生4个进程,

而且从头到尾都只是这四个进程,不会产生新的,而信号量是产生一堆线程/进程。

线程中的事件

同进程的一样,线程的一个关键特性是每个线程都是独立运行且状态不可预测。

如果程序中的其他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。

为了解决这些问题,我们需要使用threading库中的Event对象。

对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。

在初始情况下,Event对象中的信号标志被设置为假。

如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。

一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。

如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行。

event.isSet():返回event的状态值;

event.wait():如果 event.isSet()==False将阻塞线程;

event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;

event.clear():恢复event的状态值为False。

例如,有多个工作线程尝试链接MySQL,要在链接前确保MySQL服务正常才让那些工作线程去连接MySQL服务器,

如果连接不成功,都会去尝试重新连接。可以采用threading.Event机制来协调各个工作线程的连接操作。

例:模拟连接mysql数据库
import threading
import time,random
from threading import Thread,Event def conn_mysql():
count=1
while not event.is_set():
if count > 3:
raise TimeoutError('链接超时')
print('<%s>第%s次尝试链接' % (threading.current_thread().getName(), count))
event.wait(0.5)
count+=1
print('<%s>链接成功' %threading.current_thread().getName()) def check_mysql():
print('\033[45m[%s]正在检查mysql\033[0m' % threading.current_thread().getName())
time.sleep(random.randint(2,4))
event.set() if __name__ == '__main__':
event=Event()
conn1=Thread(target=conn_mysql)
conn2=Thread(target=conn_mysql)
check=Thread(target=check_mysql) conn1.start()
conn2.start()
check.start() 例:模拟连接数据库2
import time
import random
from threading import Event, Thread # 模拟连接数据库
def connect_db(e):
count = 1
while count < 4:
print('尝试第%s次检测连接' % count)
e.wait(0.5)
# 如果不传参数会一直等到事件为True为止
# 如果传参数 传一个时间参数
count += 1
if e.is_set():
print('连接成功')
break
else:
print('连接失败') def check_conn(e):
'''检测数据库是否可以连接'''
time.sleep(random.randint(1, 2))
e.set() e = Event()
Thread(target=check_conn, args=(e,)).start()
Thread(target=connect_db, args=(e,)).start() # 当你要做一件事情是有前提(前置条件)的时候
# 你就先去处理前提(前置条件)的问题 —— 前提处理好了,把状态设置成True
# 来控制即将要做的事情可以开始了。 运行效果如下:
尝试第1次检测连接
尝试第2次检测连接
连接成功

条件(Condition)

使线程等待,当满足某条件时,才释放n个线程。

Python提供的Condition对象提供了对复杂线程同步问题的支持。

Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。

线程首先acquire一个条件变量,然后判断一些条件。

如果条件不满足则wait;

如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,

其他处于wait状态的线程接到通知后会重新判断条件。

不断的重复这一过程,从而解决复杂的同步问题。

例:线程设置条件
import threading def run(n):
con.acquire()
con.wait()
print("run the thread: %s" % n)
con.release() if __name__ == '__main__': con = threading.Condition()
for i in range(10):
t = threading.Thread(target=run, args=(i,))
t.start() while True:
inp = input('>>>')
if inp == 'q':
break
con.acquire()
con.notify(int(inp))
con.release()
print('****') 运行如下:
>>>1
****
>>>run the thread: 0
2
****
>>>run the thread: 1
run the thread: 2
q 例2:通过条件变量控制线程分批执行
from threading import Condition, Thread def func(i, con):
con.acquire()
con.wait()
print(i * '*')
con.release() con = Condition()
# 定义了范围从1到9
for i in range(1, 10):
Thread(target=func, args=(i, con)).start()
while True:
# 分批控制线程执行
n = int(input('>>>'))
if n == 0:
break
con.acquire()
con.notify(n)
con.release() 运行效果如下:
>>>1
>>>*
2
>>>**
***
3
>>>******
****
*****
4
>>>*******
********
*********
0 以上,输入1则运行一次任务,1+2+3+4 10次己超出任务次数,完成后不会重复执行 例:那朵花躲迷藏
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
# ____ Condition 条件变量
# ____ 模拟那朵花中的面码捉迷藏对话 import threading, time # 将躲迷藏中搜寻的角色这个类创造出来,且继承了线程Thread这个类
class Seeker(threading.Thread): def __init__(self, cond, name):
super(Seeker, self).__init__()
self.cond = cond
self.name = name def run(self):
# 睡一秒,让躲猫猫的面码也运行起来,不然会阻塞住
time.sleep(1)
self.cond.acquire()
print(self.name + ': (藏)好了吗?')
self.cond.notify()
self.cond.wait()
print(self.name + ': (藏)好了吗?~~')
self.cond.notify()
self.cond.wait()
print(self.name + ': 看到你了!面码!')
self.cond.notify()
self.cond.wait()
self.cond.release()
print(self.name + ": 谢谢你,面码~ ") # 再来是躲迷藏的面码
class Hider(threading.Thread): def __init__(self, cond, name):
super(Hider, self).__init__()
self.cond = cond
self.name = name def run(self):
self.cond.acquire()
self.cond.wait()
# 释放对锁的占用,同时线程挂起来在这里,直到被notify
print(self.name + ": 还没好哦~")
self.cond.notify()
self.cond.wait()
print(self.name + ": (藏)好了哦~")
self.cond.notify()
self.cond.wait()
self.cond.notify()
self.cond.release()
print(self.name + ": 阿,被看到了~") cond = threading.Condition()
seeker = Seeker(cond, "仁太")
hider = Hider(cond, "面码")
seeker.start()
hider.start() 运行效果:交替进行的对话 仁太: (藏)好了吗?
面码: 还没好哦~
仁太: (藏)好了吗?~~
面码: (藏)好了哦~
仁太: 看到你了!面码!
面码: 阿,被看到了~
仁太: 谢谢你,面码~

无限循环的例子

经典的生产者与消费者问题:假设有一群生产者(Producer)和一群消费者(Consumer)通过一个市场来交互产品。

生产者的”策略“是如果市场上剩余的产品少于1000个,那么就生产100个产品放到市场上;

而消费者的”策略“是如果市场上剩余产品的数量多余100个,那么就消费3个产品。

用Condition解决生产者与消费者问题的代码如下:

#!/usr/bin/env python
# _*_ coding: utf-8 _*_
# ____消费者与生产者模型,多线程,条件变量,无限循环 import threading
import time # 生产者
class Producer(threading.Thread): def run(self):
global count
while True:
if con.acquire():
# 当产品在市场超过1000个时开始等候
if count > 1000:
con.wait()
# 少于1000个则开始生产100个产品投入市场
else:
count = count + 100
msg = self.name + ' produce 100, count=' + str(count)
print(msg)
con.notify()
con.release()
time.sleep(1) # 消费者
class Consumer(threading.Thread): def run(self):
global count
while True:
# 当市场少于200个产品时,消费者等候
if con.acquire():
if count < 200:
con.wait()
# 否则消费
else:
count = count - 30
msg = self.name + ' consume 30, count=' + str(count)
print(msg)
con.notify()
con.release()
time.sleep(1) # 初始产品为100个
count = 100
con = threading.Condition() def main():
# 两个生产者
for i in range(2):
p = Producer()
p.start()
# 五个消费者
for i in range(5):
c = Consumer()
c.start() if __name__ == '__main__':
main() 无限循环的部分运行效果:
Thread-1 produce 100, count=200
Thread-2 produce 100, count=300
Thread-3 consume 30, count=270
Thread-4 consume 30, count=240
Thread-5 consume 30, count=210
Thread-6 consume 30, count=180
Thread-1 produce 100, count=280
Thread-3 consume 30, count=250
Thread-5 consume 30, count=220
Thread-2 produce 100, count=320
Thread-4 consume 30, count=290
Thread-6 consume 30, count=260
Thread-7 consume 30, count=230
Thread-1 produce 100, count=330
Thread-4 consume 30, count=300
Thread-2 produce 100, count=400
Thread-5 consume 30, count=370
Thread-3 consume 30, count=340
Thread-6 consume 30, count=310
Thread-7 consume 30, count=280
Thread-1 produce 100, count=380
Thread-5 consume 30, count=350
Thread-3 consume 30, count=320
Thread-4 consume 30, count=290
Thread-2 produce 100, count=390
Thread-6 consume 30, count=360
Thread-7 consume 30, count=330
Thread-1 produce 100, count=430
Thread-3 consume 30, count=400
Thread-2 produce 100, count=500

浅析区别

  • 信号量 semaphore 允许统一时刻n个线程执行这段代码
  • 事件 event 有一个内部的事件来控制wait的行为且控制的是所有的线程
  • 条件 condition 有一个内部的条件来控制wait的行为,可以逐个或者分批次的控制线程的走向

end

参考:http://www.cnblogs.com/Eva-J/articles/8306047.html

铁乐学python_Day42_线程-信号量事件条件的更多相关文章

  1. 铁乐学python_Day42_线程池

    铁乐学python_Day42_线程池 concurrent.futures 异步调用模块 concurrent.futures模块提供了高度封装的异步调用接口 ThreadPoolExecutor: ...

  2. 铁乐学python_Day42_锁和队列

    铁乐学python_Day42_锁和队列 例:多个线程抢占资源的情况 from threading import Thread import time def work(): global n tem ...

  3. Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures

    参考博客: https://www.cnblogs.com/xiao987334176/p/9046028.html 线程简述 什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线 ...

  4. python 全栈开发,Day42(Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures)

    昨日内容回顾 线程什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线程是什么关系? 线程是在进程中的 一个执行单位 多进程 本质上开启的这个进程里就有一个线程 多线程 单纯的在当 ...

  5. 铁乐学python_Day41_线程01

    线程概念的引入背景 进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程. 程序和进程的区别就在于: 程序是 ...

  6. 铁乐学python_Day39_多进程和multiprocess模块2

    铁乐学python_Day39_多进程和multiprocess模块2 锁 -- multiprocess.Lock (进程同步) 之前我们千方百计实现了程序的异步,让多个任务可以同时在几个进程中并发 ...

  7. 进程同步控制(锁,信号量,事件), 进程通讯(队列和管道,生产者消费者模型) 数据共享(进程池和mutiprocess.Pool模块)

    参考博客 https://www.cnblogs.com/xiao987334176/p/9025072.html#autoid-1-1-0 进程同步(multiprocess.Lock.Semaph ...

  8. Day034--Python--锁, 信号量, 事件, 队列, 生产者消费者模型, joinableQueue

    进程同步: 1. 锁 (重点)    锁通常被用来实现对共享资源的同步访问.为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire方法来获取锁对象(如果其它线程已经获得了该锁, ...

  9. python 全栈开发,Day39(进程同步控制(锁,信号量,事件),进程间通信(队列,生产者消费者模型))

    昨日内容回顾 python中启动子进程并发编程并发 :多段程序看起来是同时运行的ftp 网盘不支持并发socketserver 多进程 并发异步 两个进程 分别做不同的事情 创建新进程join :阻塞 ...

随机推荐

  1. Nginx配置日志格式记录cookie

    Nginx配置日志格式记录cookie1. 一般用来做UV统计,或者获取用户token等. 配置方式:  在nginx的配置文件中有个变量:$http_cookie来获取cookie的信息.配置方式很 ...

  2. SQL Server操作结果集-并集 差集 交集 结果集排序

    操作结果集 为了配合测试,特地建了两个表,并且添加了一些测试数据,其中重复记录为东吴的人物. 表:Person_1魏国人物 表:Person_2蜀国人物 A.Union形成并集 Union可以对两个或 ...

  3. git 找回 git reset --hard HEAD 后的代码

    下面方法只针对当你本地代码做了 git add 或则 git commit 后又手贱的重置本地代码到上一个版本,导致本地代码丢失的情况. 如果你没有 git add 命令,而直接 git reset ...

  4. 让Div居中的方法

    1,设置元素宽度和margin值 div{ width : 90%; margin : 0px auto } 2, 定位元素,并设置其左右距离,但,不能设定宽度 div{ position : abs ...

  5. UIImagePickerController本地图片视频,相机录像机使用

    1.添加framework:MobileCoreServices 2.头:#import <MobileCoreServices/MobileCoreServices.h> 大致代码: U ...

  6. Code Signal_练习题_matrixElementsSum

    After they became famous, the CodeBots all decided to move to a new building and live together. The ...

  7. Tips——Flatlist的onEndReached多次触发问题解决

    一.问题 RN项目里使用Flatlist组件,上拉刷新item过多时,出现跳屏.闪屏.空白屏等问题. 二.原因 先在render函数里log了一下,发现没有re-render,判断不是网络请求或页面内 ...

  8. c语言中函数的形参test(int *&a)?

    今天在看一段c代码的时候看到一个函数的形参是(int *&a)居然是这个东西,这让我好生疑惑啊,不知道用这么多的地址符号用意何在呢?传址么? 那也不必这样,只需要用指针完全能够达到这样的效果啊 ...

  9. CSS响应式:根据分辨率加载不同CSS的几个方法,亲测可用

    有时候你需要把同一个页面在手机和pc同时打开,其中有一个办法就是判断不同分辨路加载不同的css 小编总结了几种分别加载css的方法: 1.比较复杂的使用js判断加载不同css (亲测可用) 但是这种方 ...

  10. webapi 后台跳转 后台输出html和script

    1.跳转 [HttpGet]public HttpResponseMessage LinkTo(){ HttpResponseMessage resp = new HttpResponseMessag ...