接收重复参数的Python任务线程
我正在编写一个多线程Python程序,在该程序中,我启动工作线程来处理输入数据列表。然后,它们处理的数据需要网络操作,这有效地限制了它们的I/O(因此GIL对我来说不是问题) 我遇到了一个问题,多个工作线程显然接收到相同的输入,但我不知道为什么。就我所知,我没有在线程之间共享任何线程不安全的数据 我已经创建了一个最小化的版本。此程序在不执行任何I/O或任何操作的情况下显示问题:接收重复参数的Python任务线程,python,multithreading,Python,Multithreading,我正在编写一个多线程Python程序,在该程序中,我启动工作线程来处理输入数据列表。然后,它们处理的数据需要网络操作,这有效地限制了它们的I/O(因此GIL对我来说不是问题) 我遇到了一个问题,多个工作线程显然接收到相同的输入,但我不知道为什么。就我所知,我没有在线程之间共享任何线程不安全的数据 我已经创建了一个最小化的版本。此程序在不执行任何I/O或任何操作的情况下显示问题: #!/usr/bin/env python import threading import logging impo
#!/usr/bin/env python
import threading
import logging
import time
logging.basicConfig(level=logging.DEBUG,
format="%(threadName)-10s %(levelname)-7s %(message)s")
sema = threading.Semaphore(10)
# keep track of already-visited data in worker threads
seen = []
seenlock = threading.Lock()
def see(num):
try:
logging.info("see: look at %d", num)
with seenlock:
if num in seen:
# this should be unreachable if each thread processes a unique number
logging.error("see: already saw %d", num)
else:
seen.append(num)
time.sleep(0.3)
finally:
sema.release()
def main():
# start at 1, so that the input number matches the log's "Thread-#"
for i in xrange(1, 100):
sema.acquire() # prevent more than 10 simultaneous threads
logging.info("process %d", i)
threading.Thread(target=lambda: see(i)).start()
if __name__ == '__main__': main()
以及一些输出:
MainThread INFO process 1
MainThread INFO process 2
Thread-1 INFO see: look at 2
Thread-2 INFO see: look at 2
MainThread INFO process 3
Thread-2 ERROR see: already saw 2
MainThread INFO process 4
Thread-3 INFO see: look at 4
Thread-4 INFO see: look at 4
MainThread INFO process 5
Thread-4 ERROR see: already saw 4
Thread-5 INFO see: look at 5
MainThread INFO process 6
Thread-6 INFO see: look at 6
MainThread INFO process 7
Thread-7 INFO see: look at 7
MainThread INFO process 8
Thread-8 INFO see: look at 8
MainThread INFO process 9
MainThread INFO process 10
我觉得我正在做的唯一可能奇怪的事情就是在一个线程上获取信号量许可证,而不是在它被释放的地方,但是信号量应该是线程安全的,并且与谁获取和释放许可证无关,只要每个许可证的数量相同
确认日期:
- Python 2.7.3(Windows;从Python.org构建)
- Python 2.6.7(Windows;cygwin dist)
- Python 2.6.6(Linux;Debian dist)
我在做什么使我的线程共享数据?这与线程无关。它与闭包的行为有关
>>> funcs = []
>>> for x in range(10):
... def foo():
... return x
... funcs.append(foo)
...
>>> [f() for f in funcs]
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
定义函数并引用封闭范围内的变量时,该变量的值始终是函数调用时封闭范围内该变量的值。由于这些函数都是在for
循环结束后调用的,因此所有10次调用的x==9
解决此问题的一个简单方法是使用默认值。简言之,改变这一点:
threading.Thread(target=lambda: see(i)).start()
为此:
threading.Thread(target=lambda x=i: see(x)).start()
或者,更好的方法是使用线程
构造函数的全部功能(感谢Joel Cornett提醒我):
您确实应该使用Queue()将数据通过管道传输到线程。这样,您就不必担心编写所有这些“看到的”/“看不见的”代码。为了调试,我只添加了“看到的”/“看不见的”代码。当我注意到我的程序在重复处理相同的事情(并且遗漏了其他事情)时,我让线程跟踪它们在做什么。关于排队的好提示,谢谢。使用
Queue()
可以确保任何线程都不会处理已经处理过的数据。要补充您的答案,解决此问题的另一种方法是创建如下线程对象:threading.thread(target=see,args=(1,).start()
@JoelCornett,您是对的,这是更好的方法。谢谢
threading.Thread(target=see, args=(i,)).start()