python 深浅拷贝案例,python浅拷贝的应用
数字首发于微信:Python编程时间
在并发编程中,如果多个线程访问同一个资源,必须保证不会因为数据变化而产生冲突和错误。这就是我一直所说的线程安全。
在什么情况下访问数据是安全的?什么情况下访问数据不安全?我如何知道代码是否是线程安全的?如何保证数据的安全性?
本文将一一解答你的疑问。
1.不安全的线程怎么办?
要搞清楚什么是线程安全,首先要知道线程安全是什么样的。
例如,下面的代码打开两个线程,并将全局变量编号递增100,000次,每次递增1:
从螺纹导入螺纹,锁紧
数字=0
定义目标() :
全球号码
for_inrange(1000000):
数字=1
线程_ 01=线程(目标=目标) )
线程_ 02=线程(目标=目标) )
线程_01.start(
线程_02.start(
线程_01 .加入(
线程_02 .加入(
是,打印(数字)
通常我们预期的输出结果是一个线程增加100万,两个线程增加200万。输出必须是200000。
但是,事实上,并不是你想的那样。不管执行多少次,每次输出结果都不一样。这些输出结果的特点是不到200万。
以下是执行3次后的结果。
1459782
1379891
1432921
这种现象就是螺纹不安全。根本原因是,实际上,我们的操作数=1。正是因为不是原子操作,所以线程不安全。
2.什么是原子操作?
原子操作是不被线程调度机制中断的操作。一旦开始,就会一直执行到结束,中途不会切换到其他线程。
类似于数据库中的事务。
Python的官方文档列出了一些常见的原子操作。
l.append(x))。
L1。扩展器(L2))。
x=L[i]
x=L.pop()).
L1=L2
L.sort()).
x=y
X.字段=y
D[x]=y
D1。更新(D2))。
d . key())
接下来不是原子操作。
i=i 1
L.append(L[-1]).
L[i]=L[j]
D[x]=D[x] 1
可以看出,像上面这样使用自增运算number=1,实际上相当于number=number 1,可以分为多个步骤。(读加法后赋值))不是原子操作。
这样,如果多个线程同时读取,可能会读取相同的数值,两次读取只会相加一次,最终导致自增量小于预期。
如果不知道代码是否原子,请通过dis模块的dis函数确认。
运行这段代码时,您会看到名为number=1的行中的代码是用双字节代码实现的。
BINARY_ADD将两个值相加。
STORE_GLOBAL:重新代入附加值。
每个字节码指令都是一个整体,不可分割。他达到的效果叫做原子操作。
如果一行代码被分成多个字节码指令,在线程切换期间只能执行一个字节码指令。在这种情况下,如果代码行包含多个线程共享的变量和资源,并且多个split指令写入共享变量,就会发生数据冲突,导致数据不准确。
为了进行比较,让我们以上面列表中的一个原子操作为例。真的如官网所说进行原子操作吗?
这里以字典的更新操作为例。并且代码执行过程应该如下图所示。
从截图可以看出,info.update(new)也是分几个操作的。
加载全局变量
LOAD_ATTR:加载属性并获取更新方法
Load _ fast:加载新变量
调用函数:调用函数
POP_TOP:执行更新操作
但是,您应该知道实际的引导数据与写操作冲突,而不是与读操作冲突。
字典的更新方式是原子操作,因为如上所述,很多字节码指令只有一次写操作(POP_TOP)。
3.实现人工原子操作。
在多线程下,
我们不能保证我们所有的代码都是原子的,所以如何让我们的代码原子化是一件非常重要的事情。
方法也很简单,就是当大气的udon面访问一个多线程共享的资源时,加锁可以达到类似原子操作的效果。如果一个代码没有被执行,它必须在接受线程调度之前被执行。
因此,我们使用锁定的方法来修改第一个示例,使其成为原子性的。
从螺纹导入螺纹,锁紧
数字=0
lock=Lock()
定义目标():
全球号码
for _ in范围(1000000):
带锁:
数字=1
thread_01=线程(目标=目标)
线程_02=线程(目标=目标)
thread_01.start()
thread_02.start()
thread_01.join()
thread_02.join()
打印(数字)
此时,无论执行多少次,输出都是2000000。
4.为什么队列线程是安全的?
Python的线程模块中有三种主要的消息通信机制:
事件
情况
长队
队列是使用最多的,我们都知道它是线程安全的。当我们向它写入和获取数据时,它不会被中断,从而导致错误,这就是为什么我们在使用队列时不需要额外的锁。
他是怎么做到的?
根本原因是Queue实现了lock原语,所以它可以像第三节一样实现人工原子操作。
原语是指由若干条机器指令组成的执行特定功能的一段程序,它是不可分割的。即原语的执行必须是连续的,不允许在执行过程中被中断。
关注微信官方账号,获取最新干货!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。