【问题标题】:Learning the Python Thread Module学习 Python 线程模块
【发布时间】:2013-12-13 01:52:01
【问题描述】:

我正在尝试了解有关线程模块的更多信息。我想出了一个快速脚本,但运行它时出现错误。文档显示格式为:

thread.start_new_thread ( function, args[, kwargs] )

我的方法只有一个参数。

#!/usr/bin/python

import ftplib
import thread

sites = ["ftp.openbsd.org","ftp.ucsb.edu","ubuntu.osuosl.org"]

def ftpconnect(target):
        ftp = ftplib.FTP(target)
        ftp.login()
        print "File list from: %s" % target
        files = ftp.dir()
        print files

for i in sites:
    thread.start_new_thread(ftpconnect(i))

我看到的错误发生在 for 循环的一次迭代之后:

Traceback(最近一次调用最后一次):文件“./ftpthread.py”,第 16 行, 在 thread.start_new_thread(ftpconnect(i)) TypeError: start_new_thread 至少需要 2 个参数,得到 1 个

对此学习过程的任何建议将不胜感激。我也研究过使用线程,但我无法导入线程,因为它显然没有安装,而且我还没有找到任何用于安装该模块的文档。

谢谢!

尝试在我的 Mac 上导入线程时遇到的错误是:

>>> import threading
# threading.pyc matches threading.py
import threading # precompiled from threading.pyc
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "threading.py", line 7, in <module>
    class WorkerThread(threading.Thread) :
AttributeError: 'module' object has no attribute 'Thread'

【问题讨论】:

  • 不要使用thread。它是低级别的,仅供专家使用。 threading 更有用。准确显示尝试import threading 时会发生什么。它是一个标准库,所以如果你不能导入它,你的安装就真的搞砸了;-)。另请说明您使用的 Python 版本以及操作系统。
  • 将您使用的确切代码和整个回溯粘贴到您的问题中。这里的 cmets 中的格式化工具太弱了,无法显示这一点。
  • 看起来您创建了名为threading.py您自己的 模块。删除或重命名它,同时摆脱你的threading.pyc。然后import threading 应该可以正常工作。
  • @tim:那个蒂姆·彼得斯? ...是的,我去了你的简历页 ;-)

标签: python multithreading


【解决方案1】:

thread.start_new_thread 函数非常低级,并没有给您太多控制权。看看threading 模块,更具体地说是Thread 类:http://docs.python.org/2/library/threading.html#thread-objects

然后您想将脚本的最后两行替换为:

# This line should be at the top of your file, obviously :p
from threading import Thread 

threads = []
for i in sites:
    t = Thread(target=ftpconnect, args=[i])
    threads.append(t)
    t.start()

# Wait for all the threads to complete before exiting the program.
for t in threads:
    t.join()

顺便说一句,您的代码失败了,因为在您的 for 循环中,您正在调用 ftpconnect(i),等待它完成,然后 然后 尝试使用它的返回值(即即None) 来启动一个新线程,这显然是行不通的。

一般来说,启动线程是通过给它一个可调用对象(函数/方法——你想要可调用对象,不是调用的结果——my_function,而不是@ 987654330@) 和可选参数来提供可调用对象(在我们的例子中,[i] 因为ftpconnect 接受一个位置参数并且您希望它是i),然后调用Thread 对象的start方法。

【讨论】:

    【解决方案2】:

    现在您可以导入 threading,立即开始使用最佳实践 ;-)

    import threading
    threads = [threading.Thread(target=ftpconnect, args=(s,))
               for s in sites]
    for t in threads:
        t.start()
    for t in threads:  # shut down cleanly
        t.join()
    

    【讨论】:

      【解决方案3】:

      你想要的是将函数对象和函数的参数传递给thread.start_new_thread,而不是执行函数。

      像这样:

      for i in sites:
          thread.start_new_thread(ftpconnect, (i,))
      

      【讨论】:

      • 当我进行这些更改时,我的脚本运行没有任何错误,但我没有得到任何输出到控制台。