异步处理示例
本示例展示如何使用 GDSignalBus 的异步信号功能来处理耗时操作,避免阻塞主线程。
完整示例代码
gdscript
@warning_ignore_start("static_called_on_instance")
extends Node
# 异步信号示例
# 演示如何使用异步回调处理耗时操作
@onready var bus = SignalBus.get_singleton()
func _ready():
print("\n=== Async Example Started ===")
bus.set_debug_enabled(true)
# 示例 1: 基础异步订阅
print("Subscribing to async_event...")
bus.subscribe_async("async_event", func(message):
print("[异步线程] 处理消息: ", message)
# 模拟耗时操作
OS.delay_msec(3000)
print("[异步线程] 处理完成")
)
# 示例 2: 带回调的异步订阅
var async_callback = func(data):
print("[异步线程] 开始处理数据: ", data)
OS.delay_msec(5000)
return "处理结果: " + str(data * 2)
var complete_callback = func(result):
print("[主线程] 处理完成,结果: ", result)
var error_callback = func(error):
print("[主线程] 处理失败: ", error)
# 订阅异步信号,带完成和错误回调
print("Subscribing to data_processing...")
bus.subscribe_async_with_callbacks(
"data_processing",
async_callback,
complete_callback,
error_callback
)
print("=== Subscriptions Complete ===\n")
func _process(_delta):
# 在主线程处理完成的异步任务
bus.process_async_tasks()
if Input.is_action_just_pressed("ui_up"):
# 发射异步信号
print("[主线程] 发射异步信号...")
bus.emit_async("async_event", ["Hello Async!"])
print("[主线程] 继续执行(不等待)")
if Input.is_action_just_pressed("ui_down"):
# 发射信号
print("[主线程] 发射数据处理信号...")
bus.emit_async("data_processing", [42])
print("[主线程] 继续执行")
func _exit_tree():
print("\n=== _exit_tree called ===")
print("Active async tasks: ", bus.get_active_async_task_count())
print("=== _exit_tree finished ===\n")功能说明
1. 基础异步订阅
gdscript
bus.subscribe_async("async_event", func(message):
print("[异步线程] 处理消息: ", message)
# 模拟耗时操作
OS.delay_msec(3000)
print("[异步线程] 处理完成")
)2. 带回调的异步订阅
gdscript
# 定义异步处理函数
var async_callback = func(data):
print("[异步线程] 开始处理数据: ", data)
OS.delay_msec(5000)
return "处理结果: " + str(data * 2)
# 定义完成回调
var complete_callback = func(result):
print("[主线程] 处理完成,结果: ", result)
# 定义错误回调
var error_callback = func(error):
print("[主线程] 处理失败: ", error)
# 订阅带回调的异步信号
bus.subscribe_async_with_callbacks(
"data_processing",
async_callback,
complete_callback,
error_callback
)3. 异步信号发射
gdscript
# 发射异步信号
bus.emit_async("async_event", ["Hello Async!"])
bus.emit_async("data_processing", [42])4. 异步任务处理
gdscript
func _process(_delta):
# 在主线程处理完成的异步任务
bus.process_async_tasks()控制说明
运行示例后,可以使用以下按键测试异步功能:
- UI Up (方向键上): 发射
async_event异步信号,触发 3 秒的异步处理 - UI Down (方向键下): 发射
data_processing异步信号,触发 5 秒的数据处理
输出示例
基础异步信号输出
[主线程] 发射异步信号...
[主线程] 继续执行(不等待)
[异步线程] 处理消息: Hello Async!
# 等待 3 秒后
[异步线程] 处理完成带回调的异步信号输出
[主线程] 发射数据处理信号...
[主线程] 继续执行
[异步线程] 开始处理数据: 42
# 等待 5 秒后
[主线程] 处理完成,结果: 处理结果: 84清理时的输出
=== _exit_tree called ===
Active async tasks: 0
=== _exit_tree finished ===核心概念
异步处理流程
- 订阅阶段: 使用
subscribe_async()或subscribe_async_with_callbacks()订阅异步信号 - 发射阶段: 使用
emit_async()发射异步信号,立即返回不等待 - 处理阶段: 异步线程执行耗时操作
- 完成阶段: 在主线程调用完成回调(如果提供)
- 清理阶段: 在
_process()中处理完成的异步任务
异步 vs 同步
- 同步:
emit()会阻塞直到所有订阅者完成处理 - 异步:
emit_async()立即返回,处理在后台进行
回调机制
- 异步回调: 在异步线程中执行,用于耗时操作
- 完成回调: 在主线程中执行,用于处理结果
- 错误回调: 在主线程中执行,用于处理错误
任务管理
gdscript
# 获取活动异步任务数量
bus.get_active_async_task_count()
# 处理完成的异步任务(必须在 _process 中调用)
bus.process_async_tasks()最佳实践
1. 总是调用 process_async_tasks()
gdscript
func _process(_delta):
bus.process_async_tasks() # 必须在每帧调用2. 合理使用回调
gdscript
# 对于简单的异步操作,使用基础订阅
bus.subscribe_async("simple_task", async_handler)
# 对于需要结果处理的操作,使用带回调的订阅
bus.subscribe_async_with_callbacks("complex_task",
async_handler,
complete_callback,
error_callback
)3. 避免长时间阻塞
gdscript
# 将长时间操作分解为小块
func long_running_task(data):
for i in range(100):
process_chunk(data[i])
if i % 10 == 0: # 每10个块检查一次
OS.delay_msec(1) # 让出控制权4. 错误处理
gdscript
# 总是提供错误回调
var error_callback = func(error):
print("异步操作失败: ", error)
# 实施回退策略
bus.subscribe_async_with_callbacks("risky_task",
async_handler,
complete_callback,
error_callback
)这个异步示例展示了如何在不阻塞主线程的情况下处理耗时操作,是构建响应式游戏应用的重要工具。