python原子操作
⑴ python 为什么有深拷贝浅拷贝
在写Python过程中,经常会遇到对象的拷贝,如果不理解浅拷贝和深拷贝的概念,你的代码就可能出现一些问题。所以,在这里按个人的理解谈谈它们之间的区别。
一、赋值(assignment)
在《Python FAQ1》一文中,对赋值已经讲的很清楚了,关键要理解变量与对象的关系。
12345
>>> a = [1, 2, 3]>>> b = a>>> print(id(a), id(b), sep='\n')
在Python中,用一个变量给另一个变量赋值,其实就是给当前内存中的对象增加一个“标签”而已。
如上例,通过使用内置函数 id() ,可以看出 a 和 b 指向内存中同一个对象。a is b会返回 True 。
二、浅拷贝(shallow )
注意:浅拷贝和深拷贝的不同仅仅是对组合对象来说,所谓的组合对象就是包含了其它对象的对象,如列表,类实例。而对于数字、字符串以及其它“原子”类型,没有拷贝一说,产生的都是原对象的引用。
所谓“浅拷贝”,是指创建一个新的对象,其内容是原对象中元素的引用。(拷贝组合对象,不拷贝子对象)
常见的浅拷贝有:切片操作、工厂函数、对象的()方法、模块中的函数。
12345678910
>>> a = [1, 2, 3]>>> b = list(a)>>> print(id(a), id(b)) # a和b身份不同140601785066200 140601784764968>>> for x, y in zip(a, b): # 但它们包含的子对象身份相同... print(id(x), id(y))... 140601911441984 140601911442048
从上面可以明显的看出来,a 浅拷贝得到 b,a 和 b 指向内存中不同的 list 对象,但它们的元素却指向相同的 int 对象。这就是浅拷贝!
三、深拷贝(deep )
所谓“深拷贝”,是指创建一个新的对象,然后递归的拷贝原对象所包含的子对象。深拷贝出来的对象与原对象没有任何关联。
深拷贝只有一种方式:模块中的deep函数。
1234567891011
>>> import >>> a = [1, 2, 3]>>> b = .deep(a)>>> print(id(a), id(b))140601785065840 140601785066200>>> for x, y in zip(a, b):... print(id(x), id(y))... 140601911441984 140601911442048
看了上面的例子,有人可能会疑惑:
为什么使用了深拷贝,a和b中元素的id还是一样呢?
答:这是因为对于不可变对象,当需要一个新的对象时,python可能会返回已经存在的某个类型和值都一致的对象的引用。而且这种机制并不会影响 a 和 b 的相互独立性,因为当两个元素指向同一个不可变对象时,对其中一个赋值不会影响另外一个。
我们可以用一个包含可变对象的列表来确切地展示“浅拷贝”与“深拷贝”的区别:
>>> import >>> a = [[1, 2],[5, 6], [8, 9]]>>> b = .(a) # 浅拷贝得到b>>> c = .deep(a) # 深拷贝得到c>>> print(id(a), id(b)) # a 和 b 不同139832578518984 139832578335520>>> for x, y in zip(a, b): # a 和 b 的子对象相同... print(id(x), id(y))... 139832578622816 139832578623104>>> print(id(a), id(c)) # a 和 c 不同139832578518984 139832578622456>>> for x, y in zip(a, c): # a 和 c 的子对象也不同... print(id(x), id(y))... 139832578622816 139832578623392
从这个例子中可以清晰地看出浅拷贝与深拷贝地区别。
总结:
1、赋值:简单地拷贝对象的引用,两个对象的id相同。
2、浅拷贝:创建一个新的组合对象,这个新对象与原对象共享内存中的子对象。
3、深拷贝:创建一个新的组合对象,同时递归地拷贝所有子对象,新的组合对象与原对象没有任何关联。虽然实际上会共享不可变的子对象,但不影响它们的相互独立性。
浅拷贝和深拷贝的不同仅仅是对组合对象来说,所谓的组合对象就是包含了其它对象的对象,如列表,类实例。而对于数字、字符串以及其它“原子”类型,没有拷贝一说,产生的都是原对象的引用。
⑵ Python多线程之threading之Lock对象
要介绍Python的 threading 模块中的 Lock 对象前, 首先应该了解以下两个概念:
1.基本概念 : 指某个函数/函数库在多线程环境中被调用时, 能够正确地处理多个线程之间的 共享变量 , 使程序功能正常完成. 多个线程访问同一个对象时, 如果不用考虑这些线程在运行时环境下的调度和交替执行, 也不需要进行额外的同步, 或者在调用方进行任何其他操作,调用这个对象的行为都可以获得正确的结果, 那么这个对象就是线程安全的. 或者说: 一个类或者程序所提供的接口对于线程来说是 原子操作 或者多个线程之间的切换不会导致该接口的执行结果存在二义性, 也就是说我们不用考虑同步的问题.
2.示例 : 比如有间银行只有1000元, 而两个人同时提领1000元时,就有可能拿到总计2000元的金额. 为了避免这个问题, 该间银行提款时应该使用 互斥锁 , 即意味着对同一个资源处理时, 前一个提领交易完成后才处理下一笔交易.
3.线程安全意义 :
4.是否线程安全 :
5.资源竞争 : 即多个线程对同一个资源的改写时, 存在的一种竞争. 如果仅仅是读操作, 则不存在资源竞争的情况.
1.基本概念 : 因为存在上述所说的 线程安全与资源竞争 的情况, 所以引入了 线程锁 . 即通过锁来进行资源请求的限制, 以保证同步执行,避免资源被污染或预期结果不符. 线程锁存在两种状态: 锁定(locked)和非锁定(unlocked).
2.基本方法 :
3.使用示例 :
上述示例如果在不加锁的情况下, 将会出现打印顺序混乱的情况, 不过最终结果都是正确的, 因为即使线程交替执行, 但最终的结果都是一致.