在Python异步进程中创建线程执行循环任务,为什么线程还没执行完进程就提前退出了?

null
在Python异步进程中创建线程执行循环任务,为什么线程还没执行完进程就提前退出了?

14 回复

num = 0

def test1(*data):
global num
i = data[0]
while True:
if num == 10:
num = 0
break
print(i)
num += 1
time.sleep(2)

def test2(*data):
i = data[0]
threading.Thread(target=test1, args=(i,)).start()
print(“done”)

pool = multiprocessing.Pool(processes=5)
for j in range(2):
pool.apply_async(test2, (j,))


这问题很典型,是异步编程里常见的生命周期管理问题。你的异步主进程跑完了,但里面启动的线程还没执行完,进程就直接退出了,因为主进程不会等非守护线程。

看个具体例子,你可能是这么写的:

import asyncio
import threading
import time

def thread_task():
    for i in range(5):
        print(f"Thread working... {i}")
        time.sleep(1)
    print("Thread finished!")

async def main():
    print("Main async function starting")
    thread = threading.Thread(target=thread_task)
    thread.start()
    
    # 模拟一些异步操作
    await asyncio.sleep(0.5)
    print("Async main finished")

asyncio.run(main())

运行这个,你会看到主协程很快就结束了,线程只打印了几次就被强制终止了。

根本原因asyncio.run() 创建的 event loop 跑完 main() 协程后就关闭了,整个Python进程退出,不管其他线程的状态。

解决方案:让主协程等待线程完成。用 thread.join() 或者更好的方式——在异步上下文中等待:

import asyncio
import threading
import time
from concurrent.futures import ThreadPoolExecutor

def thread_task():
    for i in range(5):
        print(f"Thread working... {i}")
        time.sleep(1)
    print("Thread finished!")
    return "Done"

async def main():
    print("Main async function starting")
    
    # 方法1:使用run_in_executor在事件循环中管理线程
    loop = asyncio.get_running_loop()
    with ThreadPoolExecutor() as executor:
        result = await loop.run_in_executor(executor, thread_task)
        print(f"Thread result: {result}")
    
    # 或者方法2:显式等待线程
    # thread = threading.Thread(target=thread_task)
    # thread.start()
    # while thread.is_alive():
    #     await asyncio.sleep(0.1)
    
    print("Async main finished")

asyncio.run(main())

关键点:在异步世界里启动同步线程任务,必须显式管理线程的生命周期,确保主协程在退出前等待所有工作完成。

简单说就是:记得等线程干完活再收工。

大概代码如上,不能用 join(),因为实际中是多任务定时处理,每个任务时间不一样

num = 0

def test1(*data):
global num
i = data[0]
while True:
if num == 10:
num = 0
break
print(i)
num += 1
time.sleep(2)

def test2(*data):
i = data[0]
threading.Thread(target=test1, args=(i,)).start()
print(“done”)

pool = multiprocessing.Pool(processes=5)
for j in range(2):
pool.apply_async(test2, (j,))

join 和时间长短有什么关系。。

多个定时任务啊,每个定时不一样,join 不是只能一个一个线程执行么

"不能用 join(),因为实际中是多任务定时处理,每个任务时间不一样"
join 做了等待的时候,你如果不用,那么就要自己来实现这个等待的部分,否则不等待就是直接退出了嘛

同意 #6

join 阻塞主线程,如果不想用 join 的话,必须让主线程的运行时间最长,否则主线程跑完进程结束

你把所有线程都启动了,然后再一个一个的 join 不就行了?要是还不理解你应该去看看书了~

不能用 join,就不能检查 is_alive 了?
再说了,谁说不能 join ?一个一个 join 过去就行,全 join 完退出

如果不是创建的后台线程, 不在主线程 join 的话, 主线程结束, 子线程就强制退出了;
如果是后台线程, 主线程结束后, 子线程自个跑自个的:

from threading import Thread
from time import sleep

def work():
sleep(5)
with open(“test.txt”, ‘w’) as fout:
pass

if name == “main”:
t = Thread(target=work)
t.setDaemon(True)
t.start()

后台线程作用是, 当主线程退出的时候, 不用管他们(那他们能欢快的在后台运行吗? 看进程, 进程都退出了,直接被干掉). 反而非后台进程, 主进程即使不 join, 退出之前也要等子线程结束.

所以还是要学习一个.

那么这段代码问题是, 主进程跑完之后, 所有子进程都被干掉了.无论你子进程在干什么, 直接被干掉.

所有需要在主进程加一段代码
pool.close()
pool.join()

这样看起来就完了, 主进程会等待子进程完成, 而子进程会等待线程完成

可是子进程不会等待线程完成, 所以
t.start()
t.join()

那么为什么子进程不会等待非守护线程结束呢??? 我去学习一个

说的有点问题, 并不是主线程等待子线程都完成在退出(那是 join 干的事), 而是 python 解释器保证 当没有活跃的进程之后才退出(所以主线程先退出, 子线程继续执行, 知道完成 python 进程退出是有可能的).

回到顶部