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 ...
随机推荐
- Redis数据库云端最佳技术实践
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯云数据库 TencentDB发表于云+社区专栏 邹鹏,腾讯高级工程师,腾讯云数据库Redis负责人,多年数据库.网络安全研发经验. ...
- 使用laravel-admin后台sdk报错Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID、Provisional headers are shown
报错Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID请先确定自己的资源url是否可以确实访问到(地址正确与否.访问权限是否开启等) 若n ...
- Gitlab利用Webhook实现Push代码后的jenkins自动构建
之前部署了Gitlab的代码托管平台和Jenkins的代码发布平台.通常是开发后的代码先推到Gitlab上管理,然后在Jenkins里通过脚本构建代码发布.这种方式每次在发版的时候,需要人工去执行je ...
- Github: 从github上拉取别人的源码,并推送到自己的github仓库
比如说,将 https://github.com/lizhenliang/tomcat-java-demo 迁移到 https://github.com/lousia001/tomcat-java-d ...
- Python基础——6面向对象编程
类和实例 类是抽象的模版,例如汽车:而实例则是拥有相同方法的类的实现,例如汽车里面有大众.宝马.奔驰等等,这些车都能在地面上跑,但是它们的具体数据可以不一样. calss Student(object ...
- Python基础——7面向对象高级编程
实例与类动态添加方法 实例添加属性: def Student(object): pass s = Student() s.name = ‘syz’ 实例添加方法 from types import M ...
- Java使用volatile实现多线程输出ABC共10次
问题 有A,B,C三个线程, A线程输出A, B线程输出B, C线程输出C.要求,同时启动三个线程, 按顺序输出ABC, 循环10次. 今天在写多线程的时候找例子,见到了这样一个题,觉得不难,但是在网 ...
- kernel笔记——内核同步与锁
内核同步 内核同步解决并发带来的问题,多个线程对同一数据进行修改,数据会出现不一致的情况,同步用于保护共享数据等资源. 有两种形式的并发: 同时进行式并发,在不同cpu上执行的进程同时访问共享数据 二 ...
- 在Windows下使用Git+TortoiseGit+码云管理项目代码
1. 安装Git 下载地址:点击打开链接 安装指南:默认选项即可 2. 安装TortoiseGit 下载地址:点击打开链接 安装指南:点击打开链接 3. 在码云创建账号, ...
- centos7下kubernetes(17。kubernetes-回滚)
kubectl apply每次更新应用时kubernetes都会记录下当前配置,保存为一个revision(版次),这样就可以回滚到某个特定的revision 默认配置下,kubernetes只会保留 ...