标签可能不准确,因为我不确定问题出在哪里。
我有一个模块,我试图从套接字读取一些数据,并将结果写入文件(追加)它看起来像这样,(只包括相关部分)
if __name__ == "__main__":
<some init code>
for line in file:
t = Thread(target=foo, args=(line,))
t.start()
while nThreads > 0:
time.sleep(1)
以下是其他模块,
def foo(text):
global countLock, nThreads
countLock.acquire()
nThreads += 1
countLock.release()
"""connect to socket, send data, read response"""
writeResults(text, result)
countLock.acquire()
nThreads -= 1
countLock.release()
def writeResults(text, result):
"""acquire file lock"""
"""append to file"""
"""release file lock"""
现在问题就在于此。最初,我在函数'foo'中输入了一个拼写错误,我将变量'line'传递给writeResults而不是'text'。 'line'没有在函数foo中定义,它在主块中定义,所以我应该看到一个错误,但相反,它工作正常,除了数据被多次附加到文件,而不是只是写入曾经,这是我修复错字时得到的所需行为。
我的问题是,
1)为什么我没有收到错误?
2)为什么多次调用writeResults函数?
答案 0 :(得分:1)
你真的应该使用Thread.join()
作为主循环来等待线程完成:
if __name__ == "__main__":
<some init code>
threads = []
for line in file:
t = Thread(target=foo, args=(line,))
t.start()
threads.append(t)
for t in threads:
t.join()
并删除nThreads
全局和countLock
。
关于你的问题,我不知道为什么你没有得到错误(可能是异常被某些东西吃掉了?),我想知道writeResults
的重复次数是否与数字有关文件中的行。如果确实如此,我将不得不怀疑line
是否是全局的,并且每个线程都写了一次。
答案 1 :(得分:1)
当你有(简化到重要部分)时
def foo(text):
writeResults(line, result)
foo
,没有本地变量line
,正在使用该名称的全局变量...恰好是一组(在主线程中) )for line in file:
。
具体来说,我希望写入的总行数是正常的:每行有一个线程(一个奇怪的架构,BTW),每个线程写一行...唯一的问题是,哪个每个线程写入行。
在你的意图中,第一个线程写第一行,第二个线程写第二行等;但实际上,在线程调用line
的关键时刻,每个线程都会写出恰好绑定到全局writeResults
名称的行。因此,有些行最终可能会多次写入,有些则不会写入。
例如,假设主线程运行得足够快,可以在任何实际写入之前启动所有子线程。在这种情况下,全局名称line
采用的 last 值(即文件中的最后一行)将是所有线程写入的值。
请注意,即使在“更正”的版本中也无法保证 order ,其中各行都会被写入,这是使这种架构变得奇怪的一部分 - 通常,因为线路来了按照特定顺序,您希望在输出中保留该顺序。我猜你的应用案例很奇怪,不需要那个约束,但我仍然感到困惑的是,当你从一个文件读取并写入一个文件时,你需要这么多线程! - )
答案 2 :(得分:1)
为了避免名为line
的全局变量,您应该编写一个名为main
的函数来完成这项工作。然后该变量是main
函数的本地变量。
让你的程序看起来像这样:
def main(args):
# ... init ...
for line in file:
# ... process the line
pass
if __name__ == "__main__":
main(sys.argv[1:])