使用Threading与Queue时结果异常:移除time.sleep为何输出3而非1?
问题原因解析
核心:闭包的延迟绑定坑
你写的f是个闭包,它不会在定义的时候就把当时的i值存下来,而是等到实际执行的时候,才会去读当前i的真实值。而且循环里的i是同一个变量,每次迭代只是修改它的值,不是重新创建新变量。
无time.sleep时,结果为3
去掉休眠后,线程启动后会立刻执行q.put(i)。但循环创建线程的速度极快,三个线程还没来得及执行put操作,循环就已经跑完了,此时i的最终值是3。等三个线程真正执行put的时候,读取的都是已经变成3的i,所以队列里全是3,q.get()取第一个自然就是3。
保留time.sleep时,结果为1
加了休眠后,三个线程启动后会先休眠对应时长:
- 第一个线程休眠3秒,第二个休眠2秒,第三个休眠1秒
循环跑完的速度远快于线程睡醒的速度,所以在线程们陆续睡醒之前,i已经变成了1。其中第三个线程休眠时间最短,最先醒过来执行q.put(i),这时候读取的是已经变成1的i,所以把1放进队列。q.get()会立刻取出这个第一个进入队列的1,所以打印结果就是1。
怎么解决这个问题?
如果想让每个线程都用循环当时的i值,可以给函数加个默认参数,让它在定义时就捕获当前的i:
for i in [3,2,1]: def f(i=i): # 用默认参数绑定当前i的值 time.sleep(i) q.put(i) threading.Thread(target=f).start()
这样每个f都会保存自己定义时的i值,不管后续循环怎么修改i,线程执行时用的都是当时的数值。
内容的提问来源于stack exchange,提问作者ZackR
相关产品推荐
相关产品推荐

