[英]Where does the 'self' come from? Putting a member function as target for threading.Thread
[英]Accessing `self` from thread target
根據許多來源,包括這個問題 ,在__init__
傳遞runnable作為target
參數(有或沒有args
和kwargs
)比擴展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
構造函數中,因為它尚未構造。 我認為有兩個真正的選擇。
如果您的任務運行多次,可能在許多不同的線程上運行,我認為最好的選擇是在任務中使用threading.current_thread()
。 這使您可以直接訪問線程對象,您可以使用它來執行任何操作。 這似乎正是這個功能設計的用例。
另一方面,如果你的目標是實現一個具有一些特殊特性的線程,那么自然的選擇就是子類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.