python 线程/线程锁/信号量
单线程
#常规写法 import threading
import time def sayhi(num): # 定义每个线程要运行的函数
print("running on number:%s" % num)
time.sleep() if __name__ == '__main__':
t1 = threading.Thread(target=sayhi, args=(,)) # 生成一个线程实例
t2 = threading.Thread(target=sayhi, args=(,)) # 生成另一个线程实例 t1.start() # 启动线程
t2.start() # 启动另一个线程 print(t1.getName()) # 获取线程名
print(t2.getName()) 自定义线程类
import threading
import time class MyThread(threading.Thread):
def __init__(self, num):
threading.Thread.__init__(self) self.num = num def run(self): # 定义每个线程要运行的函数
print("running on number:%s" % self.num)
time.sleep() if __name__ == '__main__':
t1 = MyThread()
t2 = MyThread() t1.start()
t2.start()

多线程
import threading
import time def sayhi(num): # 定义每个线程要运行的函数
print("running on number:%s" % num)
time.sleep() start_time=time.time()
if __name__ == '__main__':
for i in range(): ###多线程
t = threading.Thread(target=sayhi, args=(i,)) # 生成一个线程实例
t.start()
print (start_time-time.time()) ####打印时间 此时打印结果时间为0.0000几秒,是因为程序在执行完多线程时继续往下执行,而不会等待线程执行完在打印时间,所以打印出来的时间并不是多线程执行的时间 join()
线程执行后,主线程会等待所有线程执行完毕后继续往下走,下面实例介绍计算多线程执行时间 import threading
import time def sayhi(num): # 定义每个线程要运行的函数 print("running on number:%s" % num)
time.sleep() start_time=time.time() threads = [] ####定义一个列表,将所有的线程加进去
if __name__ == '__main__':
for i in range(): ###多线程
t = threading.Thread(target=sayhi, args=(i,)) # 生成一个线程实例
t.start()
threads.append(t) ####将每个线程添加到列表
for t in threads: ###循环整个列表,进行join(每个线程join完成后主线程才会继续往下走)
t.join() ###等待所有线程执行结束,相当于单线程 print (start_time-time.time())
示例二
#!/usr/bin/env python
#-*-coding:utf--*- import threading
from time import ctime,sleep
import time def music(func):
for i in range():
print ("Begin listening to %s. %s" %(func,ctime()))
sleep()
print("end listening %s"%ctime()) def move(func):
for i in range():
print ("Begin watching at the %s! %s" %(func,ctime()))
sleep()
print('end watching %s'%ctime()) threads = []
t1 = threading.Thread(target=music,args=('music',))
threads.append(t1)
t2 = threading.Thread(target=move,args=('movie',))
threads.append(t2) if __name__ == '__main__': for t in threads:
t.start()
print ("all over %s" %ctime())
守护线程
主线程不会等待守护线程结束在退出,会等待非守护线程执行完毕才退出

将线程设置为Daemon线程,它做为程序主线程的守护线程,当主线程退出时,线程也会退出,由守护线程动的其它子线程会同时退出,不管是否执行完任务
线程锁
由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 即同一时刻允许一个线程执行操作
###没有加锁时 import threading
import time,sys def addNum():
global num # 在每个线程中都获取这个全局变量
print('--get num:', num)
time.sleep()
num -= # 对此公共变量进行-1操作 num = # 设定一个共享变量
thread_list = [] for i in range():
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t)
for t in thread_list: # 等待所有线程执行完毕 t.join()
print('final num:', num) 说明:
正常来讲,这个num结果应该是0, 但在python 2.7上多运行几次,会发现,最后打印出来的num结果不总是0,为什么每次运行的结果不一样呢?
假设你有A,B两个线程,此时都 要对num 进行减1操作, 由于2个线程是并发同时运行的,所以2个线程很有可能同时拿走了num=100这个初始变量交给cpu去运算,当A线程去处完的结果是99,但此时B线程运算完的结果也是99,两个线程同时CPU运算的结果再赋值给num变量后,结果就都是99。那怎么办呢? 很简单,每个线程在要修改公共数据时,为了避免自己在还没改完的时候别人也来修改此数据,可以给这个数据加一把锁, 这样其它线程想修改此数据时就必须等待你修改完毕并把锁释放掉后才能再访问此数据。 加锁版本: import threading
import time gl_num =
lock = threading.RLock() ## 生成全局锁 def Func():
lock.acquire() #修改数据前加锁
global gl_num
gl_num +=
time.sleep()
print(gl_num)
lock.release() ###修改后释放 for i in range():
t = threading.Thread(target=Func)
t.start()
递归锁(即大锁之下在加小锁)
import threading, time def run1():
print("grab the first part data")
lock.acquire()
global num
num += 1
lock.release() return num def run2():
print("grab the second part data")
lock.acquire()
global num2
num2 += 1
lock.release() return num2 def run3():
lock.acquire()
res = run1()
print('--------between run1 and run2-----')
res2 = run2()
lock.release()
print(res, res2) if __name__ == '__main__':
num, num2 = 0, 0
lock = threading.RLock() for i in range(10):
t = threading.Thread(target=run3)
t.start() while threading.active_count() != 1:
print(threading.active_count()) else: print('----all threads done---')
print(num, num2)
条件变量同步(condition)
有一类线程需要满足条件之后才能够继续执行,Python提供了threading.Condition 对象用于条件变量线程的支持,它除了能提供RLock()或Lock()的方法外,还提供了 wait()、notify()、notifyAll()方法。
lock_con=threading.Condition([Lock/Rlock]): 锁是可选选项,不传人锁,对象自动创建一个RLock()。
wait():条件不满足时调用,线程会释放锁并进入等待阻塞;
notify():条件创造后调用,通知等待池激活一个线程;
notifyAll():条件创造后调用,通知等待池激活所有线程。
示例
import threading,time
from random import randint class Producer(threading.Thread):
def run(self):
global L
while True:
val=randint(0,100)
print('生产者',self.name,":Append"+str(val),L)
if lock_con.acquire():
L.append(val)
lock_con.notify()
lock_con.release()
time.sleep(3)
class Consumer(threading.Thread):
def run(self):
global L
while True:
lock_con.acquire()
if len(L)==0:
lock_con.wait()
print('消费者',self.name,":Delete"+str(L[0]),L)
del L[0]
lock_con.release()
time.sleep(0.25) if __name__=="__main__": L=[]
lock_con=threading.Condition()
threads=[]
for i in range(5):
threads.append(Producer())
threads.append(Consumer())
for t in threads:
t.start()
for t in threads:
t.join()
信号量
互斥锁,同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如两个水龙头,那最多只允许2个人同时使用,后面的人只能等有人用完后才能使用。
信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。
计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)
BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。
实例:
import threading, time def run(n):
semaphore.acquire()
time.sleep(1)
print("run the thread: %s" % n)
semaphore.release() if __name__ == '__main__':
num = 0
semaphore = threading.BoundedSemaphore(5) # 最多允许5个线程同时运行,有一个执行完毕后会执行另一个
for i in range(20):
t = threading.Thread(target=run, args=(i,))
t.start()
python 线程/线程锁/信号量的更多相关文章
- Python 线程同步锁, 信号量
同步锁 import time, threading def addNum(): global num num -= 1 num = 100 thread_list = [] for i in ran ...
- python 并发编程 锁 / 信号量 / 事件 / 队列(进程间通信(IPC)) /生产者消费者模式
(1)锁:进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理. 虽然使用加锁的形式实现了 ...
- {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器
Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...
- Python的并发并行[1] -> 线程[2] -> 锁与信号量
锁与信号量 目录 添加线程锁 锁的本质 互斥锁与可重入锁 死锁的产生 锁的上下文管理 信号量与有界信号量 1 添加线程锁 由于多线程对资源的抢占顺序不同,可能会产生冲突,通过添加线程锁来对共有资源进行 ...
- Python之路(第四十四篇)线程同步锁、死锁、递归锁、信号量
在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock ...
- Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量
Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程: 1.线程是一堆指令,是操作系统调度 ...
- python 之 并发编程(守护线程与守护进程的区别、线程互斥锁、死锁现象与递归锁、信号量、GIL全局解释器锁)
9.94 守护线程与守护进程的区别 1.对主进程来说,运行完毕指的是主进程代码运行完毕2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕详细解释:1.主 ...
- Python并发编程-进程 线程 同步锁 线程死锁和递归锁
进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...
- 并发编程---线程 ;python中各种锁
一,概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 --车间负责把资源整合到 ...
- 线程锁&信号量&gil
线程锁 线程锁的主要目的是防止多个线程之间出现同时抢同一个数据,这会造成数据的流失.线程锁的作用类似于进程锁,都是为了数据的安全性 下面,我将用代码来体现进程锁的作用: from threading ...
随机推荐
- Centos安装php php-fpm 以及 配置nginx
下载php源码包 http://www.php.net/downloads.php 安装php .tar.bz2 cd php- ./configure --prefix=/usr/local/php ...
- springboot操作mongodb
springboot操作mongodb 采用MongoRepository操作mongodb springboot版本2.1.2.RELEASE 注意的是:在运行应用程序时,会报错OSS Algori ...
- 基于winserver的Apollo配置中心分布式&集群部署实践(正确部署姿势)
基于winserver的Apollo配置中心分布式&集群部署实践(正确部署姿势) 前言 前几天对Apollo配置中心的demo进行一个部署试用,现公司已决定使用,这两天进行分布式部署的时候 ...
- day17--模块之time、calendar、datetime、sys、os、os.path、json、pickle、random
一.时间模块(time,calendar,datetime) 在Python中,通常有这几种方式来表示时间: 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00 ...
- App遍历探讨(含源代码)
好像好久没有更新博客了,之前写的几篇博客关于自动化的框架的居多,其中好多博友向我提了好多问题,我没有回复.这里给博友道个歉~ ~ 总结几点原因如下: 1.我一般很少上博客,看到了都是好几天之前的问题 ...
- maven eclipse web 项目 问题 cannot change version of project facet dynamic web module to 3.0
cannot change version of project facet dynamic web module to 3.0 修改 web.xml 头部 xsi:schemaLocation=&q ...
- UE、UI、UCD、UED?职责划分?
UE.UI.UCD.UED?你知道你是干啥的吗 名词 UE (User Experience) : 用户体验 UI (User Interface) : 用户界面 UCD (User-Centered ...
- TensorFlow基础
TensorFlow基础 SkySeraph 2017 Email:skyseraph00#163.com 更多精彩请直接访问SkySeraph个人站点:www.skyseraph.com Over ...
- yum 彻底删除nodejs,重新安装
第一步 用自带的包管理先删除一次 yum remove nodejs npm -y1手动删除残留 进入 /usr/local/lib 删除所有 node 和 node_modules文件夹进入 /us ...
- JS 灵活使用 console 调试
前言: Web 开发中最常用的调试就是 console.log(),console 除了 本身 log() 方法外,还有其他很多方法. console.log() console.log() 有许多意 ...