Python线程中start与run方法的区别及常见误区解析
本文深入解析Python中Thread类的start与run方法执行机制。start负责创建新线程并调用内部_bootstrap流程,最终执行run;而直接调用run仅在当前线程执行。重点指出一个常见错误:在__init__中直接调用target函数会导致其在主线程执行且返回None,致使线程无法运行。通过源码分析澄清这一误区,帮助开发者正确理解线程生命周期。
start与run方法的核心区别
核心结论:在Python线程机制中,调用start方法启动线程时,若已指定target参数且未重写run方法,线程将直接执行target所指向的方法。
线程启动的底层执行流程
具体实现逻辑如下:首先,需要初始化一个线程对象。
threading.Thread.__init__(self,target=thread_run())
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):
assert group is None, "group argument must be None for now"
if kwargs is None:
kwargs = {}
self._target = target
self._name = str(name or _newname())
self._args = args
self._kwargs = kwargs
其次,调用start方法以启动该线程。此时,系统内部会调用_start_new_thread函数,并将self._bootstrap作为回调函数传入。
thread1.start()
def start(self):
if not self._initialized:
raise RuntimeError("thread.__init__() not called")
if self._started.is_set():
raise RuntimeError("threads can only be started once")
with _active_limbo_lock:
_limbo[self] = self
try:
_start_new_thread(self._bootstrap, ())
except Exception:
with _active_limbo_lock:
del _limbo[self]
raise
self._started.wait()
_start_new_thread的作用等同于启动一个全新的操作系统线程,并在该新线程中执行传入的回调函数。
_start_new_thread = _thread.start_new_thread
def start_new_thread(function: Callable[..., Any], args: tuple[Any, ...], kwargs: dict[str, Any] = ...) -> int: ...
上述传入的回调函数即为前文提到的self._bootstrap。该_bootstrap方法内部会进一步调用_bootstrap_inner(),而_bootstrap_inner最终会调用用户的run方法。
def _bootstrap_inner(self):
try:
self._set_ident()
self._set_tstate_lock()
if _HAVE_THREAD_NATIVE_ID:
self._set_native_id()
self._started.set()
with _active_limbo_lock:
_active[self._ident] = self
del _limbo[self]
if _trace_hook:
_sys.settrace(_trace_hook)
if _profile_hook:
_sys.setprofile(_profile_hook)
try:
self.run()
因此,整个调用链的最终落脚点是执行run方法。
def run(self):
try:
if self._target:
self._target(*self._args, **self._kwargs)
finally:
# Avoid a refcycle if the thread is running a function with
# an argument that has a member that points to the thread.
del self._target, self._args, self._kwargs
run方法的执行判定逻辑
总结run方法的执行逻辑:如果用户重写了run方法,则直接执行重写后的run逻辑;如果未重写run方法,但定义了target参数,则执行创建线程时指定的target方法;若两者均未定义,则线程执行空操作。
target参数常见错误用法分析
在实际开发中常遇到一个典型问题:当指定target参数时,打印出的线程名显示为MainThread(主线程),而非预期的子线程名。导致这一现象的代码通常形如:threading.Thread.__init__(self, target=thread_run())。经分析,这是因为在__init__中直接赋值target时,实际上是在主线程中执行了thread_run函数。执行结束后,将thread_run的返回值赋给target参数。由于thread_run没有显式返回值,target变为None。若此时未重写run函数,线程启动后将无任何操作。关键在于,thread_run的执行发生在主线程,而非预期的子线程中。
def thread_run():
print ("overwrite: 开始线程:" + threading.current_thread().name)
time.sleep(2)
print ("overwrite: 退出线程:" + threading.current_thread().name)
class myThread (threading.Thread):
def __init__(self, threadID, name, delay):
threading.Thread.__init__(self,target=thread_run())
self.threadID = threadID
self.name = name
self.delay = delay
thread1.start()
thread1.join()
print ("退出主线程")
上述错误代码的运行结果如下:
overwrite: 开始线程:MainThread overwrite: 退出线程:MainThread 退出主线程
至此,关于Python中start和run方法区别及相关误区的讲解完毕。如需了解更多Python start和run相关内容,建议查阅本站过往文章或继续浏览后续教程,感谢支持。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









