python多线程学习笔记(超详细)
时间:2022-04-23
本文章向大家介绍python多线程学习笔记(超详细),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
python
threading
多线程
一. Threading简介
首先看下面的没有用Threading的程序
import threading,time
def fun():
s = 0
for i in range(30):
s += i
time.sleep(0.1)
print(s)
if __name__ == '__main__':
t = time.time()
fun()
fun()
print(time.time()-t)
>>>
435
435
6.023701906204224
[Finished in 6.6s]
如果使用线程会有什么样的效果呢
import threading,time
def fun():
s = 0
for i in range(30):
s += i
time.sleep(0.1)
print(s)
if __name__ == '__main__':
# 创建了一个线程列表,包含2个线程
ths = [threading.Thread(target=fun) for i in range(2)]
for th in ths:
th.start()
t = time.time()
for th in ths:
th.join()
print(time.time()-t)
>>>
435
435
3.116874933242798
[Finished in 3.7s]
这说明两个线程几乎是同时进行的
二. Threading的应用进阶
- join(timeout)用来实现线程等待。 被调用join()方法的线程会一直阻塞调用者的线程, 直到自己结束(正常结束,或引发未处理异常), 或超出timeout的时间。
import threading,time
class MyThread(threading.Thread):
def run(self):
for i in range(30):
print('threading:',i)
time.sleep(0.1)
if __name__ == '__main__':
t = MyThread()
t.start()
t.join(1)
for i in range(10):
print('Main:',i)
time.sleep(0.1)
>>>
threading: 0
threading: 1
threading: 2
主线程等待t这个线程0.1秒后也开始运行
Main: 0
threading: 3
Main: 1
threading: 4
Main: 2
threading: 5
Main: 3
threading: 6
Main: 4
threading: 7
Main: 5
threading: 8
Main: 6
threading: 9
Main: 7
Main: 8
Main: 9
[Finished in 2.0s]
注意每次运行的结果都不太一样
2)daemon属性 被设定为后台运行的线程,会在主程序退出时主动自杀。 设置为后台运行线程的方法是:设置线程的daemon属性为True
import threading,time
def dmn():
print('dmn start...')
time.sleep(2)
print('dmn end.')
def ndmn():
print('ndmn start...')
time.sleep(1)
print('ndmn end.')
d = threading.Thread(target=dmn)
d.daemon = True
n = threading.Thread(target=ndmn)
print('start...')
d.start()
n.start()
print('end.')
>>>
start...
dmn start...
ndmn start...
end.
ndmn end.
[Finished in 1.3s]
由上面打印的结果我们可以看到dmn线程设置为后台线程后,它的 print('dmn end.') 语句并不没有执行,这是因为后台线程在主线程结束后会自杀,所以主线程执行完后,dmn线程没能说出自己的“遗言”。 作为对比,我将daemon设为False,结果如下
...
d = threading.Thread(target=dmn)
d.daemon = False
...
>>>
start...
dmn start...
ndmn start...
end.
ndmn end.
dmn end.
[Finished in 2.5s]
线程同步
1 )指令锁 threading.Lock
acquire尝试获得锁定,进入阻塞状态。 acquire(blocking=True, timeout=-1))
release释放获得锁定(资源使用完后) release()
import threading,time,random
share = 4
lock = threading.Lock() #初始化指令锁
class MyThread(threading.Thread):
def __init__(self,i):
super().__init__()
self.i = i
def run(self):
global share
for d in range(2):
lock.acquire()
print(share)
share += self.i
time.sleep(random.random())
print('+',self.i,'=',share)
lock.release()
if __name__ == '__main__':
t = MyThread(2)
tt = MyThread(6)
t.start()
tt.start()
>>>
4
+ 2 = 6
6
+ 6 = 12
12
+ 2 = 14
14
+ 6 = 20
[Finished in 2.9s]
为了更好的感受指令锁的作用,将acquire和release去掉后结果如下
...
def run(self):
global share
for d in range(2):
# lock.acquire()
print(share)
share += self.i
time.sleep(random.random())
print('+',self.i,'=',share)
# lock.release()
...
>>>
4
6
+ 6 = 12
12
+ 2 = 18
18
+ 6 = 20
+ 2 = 20
[Finished in 2.2s]
比较后可以知道,加了指令锁后可以清楚地知道对共享资源share操作的具体情况
2 )条件变量threading.Condition 属性
- 实例化时,可指定锁。
- acquire()
- release()
- wait(timeout=None) 释放锁,进入等待阻塞, 直到唤醒或超时。
- notify(n=1) 唤醒等待该条件变量的线程。默认1个。
- notify_all() 唤醒等待该条件变量的所有线程。
实现严格的依照次序操作的线程之间的通信。 典型的实例:生产者/消费者(只有生产后,才能消费)。 线程之间可以互相通知,以达到默契的配合。 条件变量可以使用默认的锁或用户创建的锁来工作。
话不多说看代码
import threading,time
share = 0
share_cond = threading.Condition()
# 生产者
class ProThread(threading.Thread):
def __init__(self):
super().__init__()
self.name = 'Produce'
def run(self):
global share
if share_cond.acquire():
while True:
if not share: # 若没东西了,即开始生产
share += 1
print(self.name,share)
share_cond.notify() #唤醒消费者?这个是我自己的理解
share_cond.wait()
time.sleep(1)
# 消费者
class CustomThread(threading.Thread):
def __init__(self):
super().__init__()
self.name = 'Custom'
def run(self):
global share
if share_cond.acquire():
while True:
if share:
share -= 1 # 若有东西就买买买
print(self.name,share)
share_cond.notify() #唤醒生产者,同上,仅是个人理解,如有错请告知,谢谢
share_cond.wait()
time.sleep(1)
if __name__ == '__main__':
t = ProThread()
tt = CustomThread()
t.start()
tt.start()
>>>
Produce 1
Custom 0
Produce 1
Custom 0
Produce 1
Custom 0
...
...
...
上面的结果会一直重复执行下去
3 ) 信号量threading.Semaphore
属性
- 实例化时,指定使用量。
- 其内置计数器,锁定时+1, 释放时-1,计数器为0则阻塞。
- acquire(blocking=True,timeout=None)
- release()释放锁。
import threading,time
sema = threading.Semaphore(2)
class MyThread(threading.Thread):
def __init__(self,name):
super().__init__()
self.name = name
def run(self):
if sema.acquire():
print(self.name,'Had got resource.')
time.sleep(1)
sema.release()
print(self.name,'Had released resource.')
if __name__ == '__main__':
ths = [MyThread(str(i)+'Sema') for i in range(5)]
for th in ths:
th.start()
>>>
0Sema Had got resource.
1Sema Had got resource.
2Sema Had got resource.
1Sema Had released resource.
3Sema Had got resource.
0Sema Had released resource.
3Sema Had released resource.
4Sema Had got resource.
2Sema Had released resource.
4Sema Had released resource.
[Finished in 3.6s]
4 ) 线程通信threading.Event
- 其管理一个内部标志.实现一个线程,唤醒其它线程。
- set() 设置内部标志为True
- clear() 设置内部标志为False
- wait(timeout) 阻塞线程,到内部标志为True。
import threading,time
event = threading.Event()
class MyThreadWait(threading.Thread):
def run(self):
self.name = 'Wait Thread'
print(self.name,"Wait...")
event.wait()
print(self.name,"Start...")
event.clear()
class MyThreadMain(threading.Thread):
def run(self):
time.sleep(3)
print('Main thread set event flag!')
event.set()
if __name__ == '__main__':
thw = MyThreadWait()
thm = MyThreadMain()
thw.start()
thm.start()
>>>
Wait Thread Wait...
Main thread set event flag!
Wait Thread Start...
[Finished in 3.6s]
好了,大概就是这些了,其他的以后再补充,另外感谢麦子学院提供的免费课程~~~真心不是打广告
- 3390: [Usaco2004 Dec]Bad Cowtractors牛的报复
- 1684: [Usaco2005 Oct]Close Encounter
- 算法模板——Dinic最小费用最大流
- 算法模板——Dinic网络最大流 1
- SQL Server 使用全文索引进行页面搜索
- 2764: [JLOI2011]基因补全
- 1000: A+B Problem(NetWork Flow)
- 博弈论进阶之Multi-SG
- 2929: [Poi1999]洞穴攀行
- SQL Server 执行计划缓存
- 1081: [SCOI2005]超级格雷码
- 1715: [Usaco2006 Dec]Wormholes 虫洞
- 博弈论入门之斐波那契博弈
- 3018: [Usaco2012 Nov]Distant Pastures
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Stata | 2020年国家社科基金立项名单分析
- 还在用Guava Cache?它才是Java本地缓存之王
- 死信队列的消息处理方案
- 【Ceph】Rook 中使用 External Cluster 的方式管理外部集群
- Redis排行榜的设计与实现
- 血的教训 | 一次订单号重复的事故差点被开除
- 60分钟看懂HMM的基本原理
- R语言确实会蛮耗费磁盘空间哦
- 很多时候你就是不知道如何提问
- seurat标准流程实例之2个10x样本的项目(GSE135927数据集)
- 使用 Jenkins 和 Ansible 实现 CI/CD
- 太刺激了,面试官让我手写跳表,而我用两种实现方式吊打了TA!
- 被 Google 选择的下一代数据面 Cilium 是什么 - 上手实践
- K8S 生态周报| 是时候从 k8s v1.16 升级了
- ESP8266(一)| 基于OneNet的温度采集显示系统