如何在Python3.5中模拟SpringBoot @EnableAsync/@Async式异步执行?
模拟Spring Boot @Async 异步调用的Python实现方案
嘿,我看到你在尝试复刻Spring Boot里@EnableAsync和@Async的异步调用效果,遇到了线程启动后代码阻塞的问题,咱们一步步拆解解决:
首先解决你当前的核心问题:打印语句未执行
你代码里的关键错误出在线程创建的参数上:
p = threading.Thread(target=self.print_cpu_data())
这里的self.print_cpu_data()加了括号,会立即执行这个方法,而不是把方法对象传给线程作为执行目标。这就导致程序直接卡在print_cpu_data的while循环里,根本走不到后面的print('Thread is Alive...')语句。
正确的写法应该去掉括号,把函数本身传给target:
p = threading.Thread(target=self.print_cpu_data)
优化线程安全的启停控制
你用全局变量x来控制循环启停存在线程安全风险(多线程下读写全局变量可能出现竞态条件),推荐用Python标准库的threading.Event来实现更可靠的线程间通信。它是线程安全的,专门用来做这类“信号触发”的场景。
完整修改后的代码
import threading import re import subprocess import time class Printer: def __init__(self): # 用Event代替全局变量x,控制循环启停 self.running_event = threading.Event() def caller(self): if self.running_event.is_set(): self.running_event.clear() # 停止之前的循环 print('While-loop stopped & spawning a new one.') self.running_event.set() # 标记新循环可以启动 # 注意这里去掉print_cpu_data的括号,传递函数对象 p = threading.Thread(target=self.print_cpu_data) p.start() # 现在这句会正常执行了! print('Thread is Alive: {0}'.format(p.is_alive())) def print_cpu_data(self): # 启动后立刻返回控制权给caller,后台执行循环 while self.running_event.is_set(): cpu = subprocess.getoutput('cat /sys/class/thermal/thermal_zone0/temp') gpu = subprocess.getoutput('/opt/vc/bin/vcgencmd measure_temp') cpu = re.findall(r'[-+]?\d*\.?\d+|[-+]?\d+', cpu) gpu = re.findall(r'[-+]?\d*\.?\d+|[-+]?\d+', gpu) cpu = float(cpu[0]) / 1000 gpu = float(gpu[0]) print('CPU: {0:.2f}{2}C\tGPU: {1:.2f}{2}C'.format(cpu, gpu, '°')) time.sleep(1.0) # 测试用法 if __name__ == '__main__': printer = Printer() printer.caller() # 这里可以继续执行其他逻辑,控制权已经回到主程序 print("主程序继续执行...")
进一步封装:模拟@Async注解的装饰器
如果想更接近Spring的@Async用法,不用每次手动创建线程,可以写一个装饰器来封装异步逻辑:
import threading from functools import wraps def async_task(func): @wraps(func) def wrapper(*args, **kwargs): thread = threading.Thread(target=func, args=args, kwargs=kwargs) thread.start() # 如果需要获取线程状态,可以返回thread对象 return thread return wrapper
然后你的方法就可以像这样用:
class Printer: def __init__(self): self.running_event = threading.Event() def caller(self): if self.running_event.is_set(): self.running_event.clear() print('While-loop stopped & spawning a new one.') self.running_event.set() # 用装饰器实现异步调用,立刻返回控制权 thread = self.print_cpu_data() print('Thread is Alive: {0}'.format(thread.is_alive())) @async_task def print_cpu_data(self): while self.running_event.is_set(): # 原有逻辑不变 cpu = subprocess.getoutput('cat /sys/class/thermal/thermal_zone0/temp') gpu = subprocess.getoutput('/opt/vc/bin/vcgencmd measure_temp') cpu = re.findall(r'[-+]?\d*\.?\d+|[-+]?\d+', cpu) gpu = re.findall(r'[-+]?\d*\.?\d+|[-+]?\d+', gpu) cpu = float(cpu[0]) / 1000 gpu = float(gpu[0]) print('CPU: {0:.2f}{2}C\tGPU: {1:.2f}{2}C'.format(cpu, gpu, '°')) time.sleep(1.0)
这样每次调用被@async_task装饰的方法,都会自动在后台线程执行,调用方立刻收回控制权,完全模拟了Spring @Async的效果。
内容的提问来源于stack exchange,提问作者S34N
相关产品推荐
相关产品推荐

