覆盖python threading.Thread.run()

Gav*_*Roy 37 python multithreading

鉴于Python文档Thread.run():

您可以在子类中覆盖此方法.标准的run()方法调用传递给对象构造函数的可调用对象作为目标参数(如果有),分别使用args和kwargs参数中的顺序和关键字参数.

我构造了以下代码:

class DestinationThread(threading.Thread):
    def run(self, name, config):
        print 'In thread'

thread = DestinationThread(args = (destination_name, destination_config))
thread.start()
Run Code Online (Sandbox Code Playgroud)

但是当我执行它时,我收到以下错误:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py", line 522, in __bootstrap_inner
    self.run()
TypeError: run() takes exactly 3 arguments (1 given)
Run Code Online (Sandbox Code Playgroud)

我似乎错过了一些明显的东西,但我看到的各种例子都与这种方法有关.最终我试图将字符串和字典传递给线程,如果构造函数不是正确的方法,而是在启动线程之前创建一个新函数来设置值,我对此持开放态度.

有关如何最好地完成此任务的任何建议?

Jer*_*rub 68

你真的不需要继承Thread.API支持这一点的唯一原因是让来自Java的人们感觉更舒服,这是唯一能够做到这一点的方法.

我们建议您使用的模式是将方法传递给Thread构造函数,然后调用.start().

 def myfunc(arg1, arg2):
     print 'In thread'
     print 'args are', arg1, arg2

 thread = Thread(target=myfunc, args=(destination_name, destination_config))
 thread.start()
Run Code Online (Sandbox Code Playgroud)

  • 是.我可以避免使用提供的API,而是导入一个不同的不必要的API.确实如此. (34认同)
  • 这是我缺少的一个关键信息,这就是为什么我接受它,但在我的情况下,我实际上是在扩展类添加所需的函数来从数据中提取数据. (5认同)
  • 一千次是的.我必须向Java开发人员解释这一点. (3认同)
  • 是的,但是,这仍然没有回答关于子类化的实际问题。 (2认同)

Gav*_*Roy 8

这是使用线程传递参数而不是扩展的示例__init__:

import threading

class Example(threading.Thread):

    def run(self):
        print '%s from %s' % (self._Thread__kwargs['example'],
                              self.name)

example = Example(kwargs={'example': 'Hello World'})
example.start()
example.join()
Run Code Online (Sandbox Code Playgroud)

以下是使用多重处理的示例:

import multiprocessing

class Example(multiprocessing.Process):

    def run(self):
        print '%s from %s' % (self._kwargs['example'],
                              self.name)

example = Example(kwargs={'example': 'Hello World'})
example.start()
example.join()
Run Code Online (Sandbox Code Playgroud)

  • 访问`self._Thread__kwargs`非常难看. (17认同)
  • 在Python 3 中,Thread 的属性从private 变为protected,即`self.__kwargs`(在Thread 类中)变成了`self._kwargs`。这允许稍微不那么丑陋的访问,因为不再使用名称修改。但是,如果要同时支持 Python 2 和 3,则此更改需要对 Python 版本敏感。 (2认同)

pjk*_*ert 7

文档threading.Thread似乎暗示任何未使用的位置和关键字args都会被传递给run.他们不是.

任何额外的位置args和关键字kwargs确实被默认threading.Thread.__init__方法捕获,但它们只传递给使用target=关键字指定的方法.它们不会传递给run()方法.

实际上,Threading文档清楚地表明它使用被捕获的args run()调用提供的target=方法的默认方法,并且kwargs:

"你可以在子类中重写这个方法.标准的run()方法调用传递给对象构造函数的可调用对象作为目标参数,如果有的话,分别从args和kwargs参数中获取顺序和关键字参数."


ihm*_*ihm 5

如果您想保留面向对象的方法并且还具有运行参数,您可以执行以下操作:

import threading
class Destination:
    def run(self, name, config):
        print 'In thread'

destination = Destination()
thread = threading.Thread(target=destination.run,
    args=(destination_name, destination_config))
thread.start()
Run Code Online (Sandbox Code Playgroud)

如上所述,也可以通过以下方式完成partial

from functools import partial
import threading
class Destination:
    def run(self, name, config):
        print 'In thread'

destination = Destination()
thread = threading.Thread(target=partial(
    destination.run, destination_name, destination_config))
thread.start()
Run Code Online (Sandbox Code Playgroud)

与纯函数方法相比,这样做的优点是它可以让您保持其他现有的面向对象代码相同。唯一的变化是让它不是 Thread 的子类,这应该不是什么大问题,因为根据threading.Thread文档:

只重写该类的init ()和run()方法

如果您要重写 Thread 以便可以从子类中访问线程对象,那么我建议您仅在对象中使用 threading.currentThread() 。这样,您就可以根据 Tim Peters 的“Python 之禅”将线程的命名空间与您自己的命名空间分开:

命名空间是一个非常棒的想法——让我们多做一些这样的事情吧!