从线程目标访问“self”

Mad*_*ist 4 python multithreading python-3.x

根据许多来源,包括这个问题,将可运行作为target参数传递__init__(带或不带argsand kwargs)比扩展类更可取Thread

如果我创建一个可运行的对象,如何在self不扩展Thread类的情况下传递它正在运行的线程?例如,以下内容可以正常工作:

class MyTask(Thread):
    def run(self):
        print(self.name)
MyTask().start()
Run Code Online (Sandbox Code Playgroud)

但是,我看不到让这个版本工作的好方法:

def my_task(t):
    print(t.name)
Thread(target=my_task, args=(), kwargs={}).start()
Run Code Online (Sandbox Code Playgroud)

这个问题是Python - How can I Implement a 'stoppable' thread? 的后续问题 ,我回答了,但可能不完整。

更新

我想到了一个技巧来使用以下方法来做到这一点current_thread()

def my_task():
    print(current_thread().name)
Thread(target=my_task).start()
Run Code Online (Sandbox Code Playgroud)

问题:调用函数来获取理想情况下应该传入的参数。

更新#2

我发现了一个更黑客的解决方案,它看起来current_thread更具吸引力:

class ThreadWithSelf(Thread):
    def __init__(self, **kwargs):
        args = kwargs.get('args', ())
        args = (self,) + tuple(args)
        kwargs[args] = args
        super().__init__(**kwargs)
ThreadWithSelf(target=my_task).start()
Run Code Online (Sandbox Code Playgroud)

除了极其丑陋之外(例如,通过强制用户仅使用关键字,即使这是文档中推荐的方式),这完全违背了不扩展Thread.

更新#3

另一个荒谬(且不安全)的解决方案:通过传入可变对象args并随后更新它:

def my_task(t):
    print(t[0].name)
container = []
t = Thread(target=my_task, args=(container,))
container[0] = t
t.start()
Run Code Online (Sandbox Code Playgroud)

为了避免同步问题,您可以将其提高一个档次并实现另一层荒谬:

 def my_task(t, i):
     print(t[i].name)
 container = []
 container[0] = Thread(target=my_task, args=(container, 0))
 container[1] = Thread(target=my_task, args=(container, 1))
 for t in container:
     t.start()
Run Code Online (Sandbox Code Playgroud)

我仍在寻找合法的答案。

bna*_*ker 5

看来您的目标是从任务本身内部访问当前正在执行任务的线程。您无法将线程作为参数添加到threading.Thread构造函数,因为它尚未构造。我认为有两个真正的选择。

  1. 如果您的任务运行多次,可能在许多不同的线程上运行,我认为最好的选择是threading.current_thread()从任务内部使用。这使您可以直接访问线程对象,用它您可以做任何您想做的事情。这似乎正是该函数设计的用例类型。

  2. 另一方面,如果您的目标是实现具有某些特殊特征的线程,那么自然的选择是子类化threading.Thread,实现您希望的任何扩展行为。

另外,正如您在评论中指出的,insinstance(current_thread(), ThreadSubclass)will return True,这意味着您可以使用这两个选项,并确保您的任务将能够访问您在子类中实现的任何额外行为。