当我们编写多线程程序时,经常需要处理复杂的共享变量和竞态等问题。
“线程安全”,通常被用来形容某个行为或者某类数据结构,可以在多线程环境下被共享使用并产生预期内的结果。一个典型的满足“线程安全”的模块就是queue 队列模块。
而我们常做的value += 1操作,很容易被想当然的认为是“线程安全”的。因为它看上去就是一个原子操作(指一个最小的操作单位,执行途中不会插入任何其他操作)。然而真相并非如此,虽然从 Python 代码上来看,value += 1这个操作像是原子的。但它最终被 Python 解释器执行的时候,早就不再“原子”了。
我们可以用前面提到的dis模块来验证一下:
在上面输出结果中,可以看到这个简单的累加语句,会被编译成包括取值和保存在内的好几个不同步骤,而在多线程环境下,任意一个其他线程都有可能在其中某个步骤切入进来,阻碍你获得正确的结果。
因此,请不要凭借自己的直觉来判断某个行为是否“线程安全”,不然等程序在高并发环境下出现奇怪的 bug 时,你将为自己的直觉付出惨痛的代价。
2. 字符串拼接并不慢
我刚接触 Python 不久时,在某个网站看到这样一个说法:“Python 里的字符串是不可变的,所以每一次对字符串进行拼接都会生成一个新对象,导致新的内存分配,效率非常低”。我对此深信不疑。
所以,一直以来,我尽量都在避免使用+=的方式去拼接字符串,而是用"".join(str_list)之类的方式来替代。
但是,在某个偶然的机会下,我对 Python 的字符串拼接做了一次简单的性能测试后发现:Python 的字符串拼接根本就不慢!在查阅了一些资料后,最终发现了真相。
Python 的字符串拼接在 2.2 以及之前的版本确实很慢,和我最早看到的说法行为一致。但是因为这个操作太常用了,所以之后的版本里专门针对它做了性能优化。大大提升了执行效率。
如今使用+=的方式来拼接字符串,效率已经非常接近"".join(str_list)了。所以,该拼接时就拼接吧,不必担心任何性能问题。








网友评论