Python 官方文档:入门教程 => 点击学习
目录1. 线程通信1.1 互斥锁1.2 线程间全局变量的共享1.3 共享内存间存在竞争问题1.4 使用锁来控制共享资源的访问分析此阶段,我们会发现进程和线程的痛点!!!2. 队列的基
在多线程中 , 所有变量对于所有线程都是共享的 , 因此 , 线程之间共享数据最大的危险在于多个线程同时修改一个变量 , 那就乱套了 , 所以我们需要互斥锁 , 来锁住数据。
注意:
因为线程属于同一个进程,因此它们之间共享内存区域。因此全局变量是公共的。
# -*- coding: utf-8 -*-
import threading
a = 1
def func():
global a
a = 2
t = threading.Thread(target=func)
t.start()
t.join()
print(a)
先来个正常的例子,不用多线程:
# -*- coding: utf-8 -*-
x = 0
n =1000000
def a(n):
global x
for i in range(n):
x += 1
def b(n):
global x
for i in range(n):
x -= 1
a(n)
b(n)
print(x)
输出肯定和大家想的一样,毫无疑问是0!
# -*- coding: utf-8 -*-
from threading import Thread
x = 0
n =1000000
def a(n):
global x
for i in range(n):
x += 1
def b(n):
global x
for i in range(n):
x -= 1
if __name__ == '__main__':
a = Thread(target=a,args = (n,))
b = Thread(target=b,args = (n,))
a.start()
b.start()
# 一定要加阻塞,原因大家可以自己结合第一篇讲的自己好好想想哦~
a.join()
b.join()
print(x)
提示:
你会发现这个结果千奇百怪!!!
下面引入互斥锁
第一种实现:
# -*- coding: utf-8 -*-
from threading import Thread, Lock
a = 0
n = 100000 # 指定加减次数
# 线程锁
lock = Lock()
def incr(n):
global a
# 对全局变量a做n次加1
for i in range(n):
lock.acquire()
a += 1
lock.release()
def decr(n):
global a
# 对全局变量a做n次减一
for i in range(n):
lock.acquire()
a -= 1
lock.release()
t_incr = Thread(target=incr, args=(n, ))
t_decr = Thread(target=decr, args=(n, ))
t_incr.start(); t_decr.start()
t_incr.join(); t_decr.join()
print(a)
第二种实现:
# -*- coding: utf-8 -*-
from threading import Thread, Lock
a = 0
n = 100000 # 指定加减次数
# 线程锁
lock = Lock()
def incr(n):
global a
# 对全局变量a做n次加1
for i in range(n):
with lock:
a += 1
def decr(n):
global a
# 对全局变量a做n次减一
for i in range(n):
with lock:
a -= 1
t_incr = Thread(target=incr, args=(n, ))
t_decr = Thread(target=decr, args=(n, ))
t_incr.start(); t_decr.start()
t_incr.join(); t_decr.join()
print(a)
线程之间如何进行协作?
最典型的例子就是生产者/消费者模式:若干个生产者线程向队列中写入数据,若干个消费者线程从队列中消费数据。
(功能!)
这里就引入了协程!是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。
最重要的是,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。
代码走起来(依旧是生产者/消费者模式的例子!):
def consumer():
while True:
# consumer协程等待接收数据
number = yield
print('开始消费', number)
consumer_result = consumer()
# 让初始化状态的consumer协程先执行起来,在yield处停止
next(consumer_result)
for num in range(100):
print('开始生产', num)
# 发送数据给consumer协程
consumer_result.send(num)
代码中创建了一个叫做consumer_result的协程,并且在主线程中生产数据,协程中消费数据。
其中 yield 是python当中的语法。当协程执行到yield关键字时,会暂停在那一行,等到主线程调用send方法发送了数据,协程才会接到数据继续执行。
但是,yield让协程暂停,和线程的阻塞是有本质区别的。协程的暂停完全由程序控制,线程的阻塞状态是由操作系统内核来进行切换。
因此,协程的开销远远小于线程的开销!!!
执行结果:
import queue
队列操作一览:
注意:
简单使用队列的方法:
# -*- coding: utf-8 -*-
import queue
# 创建队列
q = queue.Queue(4)
# 入队
q.put(1)
q.put(2)
q.put(3)
print(q.full())
q.put(4)
print(q.full())
# 出队
print(q.get())
print(q.get())
print(q.empty())
print(q.get())
print(q.get())
print(q.empty())
到此这篇关于Python常用模块之threading和Thread模块及线程通信的文章就介绍到这了,更多相关Python 线程通信内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: Python常用模块之threading和Thread模块及线程通信
本文链接: https://www.lsjlt.com/news/151209.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0