簡體   English   中英

從線程目標訪問`self`

[英]Accessing `self` from thread target

根據許多來源,包括這個問題 ,在__init__傳遞runnable作為target參數(有或沒有argskwargs )比擴展Thread類更可取。

如果我創建了一個runnable,我怎樣才能將它運行的線程作為self傳遞給它而不擴展Thread類? 例如,以下內容可以正常工作:

class MyTask(Thread):
    def run(self):
        print(self.name)
MyTask().start()

但是,我看不到讓這個版本工作的好方法:

def my_task(t):
    print(t.name)
Thread(target=my_task, args=(), kwargs={}).start()

這個問題是Python的后續問題- 如何實現'可停止'的線程? ,我回答,但可能不完整。

更新

我已經想過使用current_thread()執行此操作:

def my_task():
    print(current_thread().name)
Thread(target=my_task).start()

問題:調用函數來獲取理想情況下應該傳入的參數。

更新#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()

除了令人難以置信的丑陋(例如,通過強迫用戶僅使用關鍵字,即使這是文檔中推薦的方式),這完全違背了不擴展Thread的目的。

更新#3

另一個荒謬(和不安全)的解決方案:通過args傳入一個可變對象並在之后更新它:

def my_task(t):
    print(t[0].name)
container = []
t = Thread(target=my_task, args=(container,))
container[0] = t
t.start()

為了避免同步問題,你可以提升一個檔次並實現另一層荒謬:

 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()

我仍然在尋找一個合理的答案。

您的目標似乎是從任務本身訪問當前正在執行任務的線程。 您不能將線程作為參數添加到threading.Thread構造函數中,因為它尚未構造。 我認為有兩個真正的選擇。

  1. 如果您的任務運行多次,可能在許多不同的線程上運行,我認為最好的選擇是在任務中使用threading.current_thread() 這使您可以直接訪問線程對象,您可以使用它來執行任何操作。 這似乎正是這個功能設計的用例。

  2. 另一方面,如果你的目標是實現一個具有一些特殊特性的線程,那么自然的選擇就是子類threading.Thread ,實現你想要的任何擴展行為。

另外,正如您在評論中指出的那樣, insinstance(current_thread(), ThreadSubclass)將返回True ,這意味着您可以使用這兩個選項,並確保您的任務可以訪問您在子類中實現的任何額外行為。

您可以使用可變對象(如list )作為線程的參數,並在創建后填充它,但在運行之前:

def my_task(l):
    t = l[0]
    print(t.name)


mutable_list = []
thread = threading.Thread(target=my_task, args=(mutable_list,), kwargs={})
mutable_list.append(thread)
thread.start()
thread.join()

你得到:

Thread-1

這里最簡單,最易讀的答案是:使用current_thread() 您可以使用各種奇怪的方法將線程作為參數傳遞,但沒有充分的理由。 調用current_thread()是比所有替代方法更短的標准方法,並且不會混淆其他開發人員。 不要試圖過度思考/過度設計:

def runnable():
    thread = threading.current_thread()

Thread(target=runnable).start()

如果您想隱藏它並因美觀原因而改變,您可以嘗試:

def with_current_thread(f):
    return f(threading.current_thread())

@with_current_thread
def runnable(thread):
    print(thread.name)

Thread(target=runnable).start()

如果這還不夠好,你可以通過描述為什么你認為參數傳遞對你的用例更好/更正確來得到更好的答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM