python显示print的p错误_Python多线程print错乱问题

现象

看如下python2代码:

import time

import threading

def a():

time.sleep(1)

print 'hello'

ts = []

for i in range(10):

t = threading.Thread(target=a)

t.start()

ts.append(t)

for t in ts:

t.join()

运行下输出会错乱

acdaf2ffd81b

这可能是初次接触python多线程的人经常会遇到的问题。

结论

先说结论:Python2的print关键词不是线程安全的,Python3的print函数是线程安全的。

原因

我们用dis包对某个PyObject做反汇编(disassemble),这里的反汇编其实指的是把python脚本翻译成python中间字节码,由python虚拟机解释执行字节码。虚拟机模拟了cpu,字节码(opcode)则类似汇编语言。字节码解释器是python的核心所在,Python通过GIL(Global Interpreter Lock)这个互斥锁保证同一时刻只有一个线程使用解释器(或者说虚拟机)。

import dis

def a():

print 'hello'

dis.dis(a)

可以看到a()的字节码如下:

acdaf2ffd81b

其中print对应两个字节码PRINT_ITEM和PRINT_NEWLINE,分别是输出对象和输出换行符,理论上print 'hello'等价于

sys.stdout.write('hello')

sys.stdout.write('\n')

所以当虚拟机做线程切换时可能会把输出hello和输出\n的两个操作切开,造成输出上述错乱的结果,这就是为什么python2的print不是原子操作。

那我们再看如下代码及输出:

import dis

import sys

def a():

sys.stdout.write('hello'+'\n')

dis.dis(a)

acdaf2ffd81b

其实write()函数的调用是CALL_FUNCTION这一步,而write()是builtin_function,是原子操作。(可以试试看dis.dis(sys.stdout.write))

如何避免

使用python3,社区将在2020年放弃维护python2。

如果需要使用python2,需要将多线程中的print content替换成sys.stdout.write('{}%\n'.format(content))

参考

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值