异步信号
概述
异步信号允许在后台线程中处理耗时操作,避免阻塞主线程,保持游戏的流畅性。GDSignalBus 提供了完整的异步信号处理机制。
基础用法
发送异步信号
gdscript
# 获取 SignalBus 单例
var bus = SignalBus.get_singleton()
# 基本异步信号
bus.emit_async("save_game", [player_data])
# 带回调的异步信号
bus.subscribe_async_with_callbacks("data_processing",
func(args):
var data = args[0]
print("[异步线程] 开始处理数据: ", data)
OS.delay_msec(2000) # 模拟耗时操作
return "处理结果: " + str(data * 2),
func(result):
print("[主线程] 处理完成,结果: ", result),
func(error):
print("[主线程] 处理失败: ", error)
)
# 发射异步信号
bus.emit_async("data_processing", [42])异步回调
gdscript
func _on_save_complete(success, result):
if success:
print("保存成功: ", result)
else:
print("保存失败: ", result)
func _on_load_complete(success, data):
if success:
apply_loaded_data(data)
else:
show_error_message("加载失败")异步任务类型
文件操作
gdscript
# 异步文件读取
bus.subscribe_async_with_callbacks("file_read",
func(args):
var path = args[0]
var file = FileAccess.open(path, FileAccess.READ)
if file:
var content = file.get_as_text()
file.close()
return content
return null,
_on_file_read_complete,
_on_file_read_error
)
# 异步文件写入
bus.subscribe_async_with_callbacks("file_write",
func(args):
var path = args[0]
var content = args[1]
var file = FileAccess.open(path, FileAccess.WRITE)
if file:
file.store_string(content)
file.close()
return true
return false,
_on_file_write_complete,
_on_file_write_error
)网络请求
gdscript
# HTTP 请求
bus.subscribe_async_with_callbacks("http_request",
func(args):
var url = args[0]
var method = args[1]
var body = args[2] if args.size() > 2 else ""
var http = HTTPRequest.new()
# 这里需要实现实际的 HTTP 请求逻辑
# 简化示例,返回模拟结果
OS.delay_msec(1000) # 模拟网络延迟
return "Response from " + url,
_on_response_complete,
_on_response_error
)数据处理
gdscript
# 复杂计算
bus.subscribe_async_with_callbacks("calculate_path",
func(args):
var start = args[0]
var end = args[1]
print("[异步线程] 开始计算路径...")
# 模拟 A* 寻路算法
var path = []
var current = start
while current.distance_to(end) > 1.0:
var next = current + (end - current).normalized() * 10.0
path.append(next)
current = next
OS.delay_msec(50) # 模拟计算时间
path.append(end)
print("[异步线程] 路径计算完成")
return path,
_on_path_calculated,
_on_path_error
)
# 大量数据处理
bus.subscribe_async_with_callbacks("process_inventory",
func(args):
var items = args[0]
print("[异步线程] 开始处理库存数据...")
var processed_items = []
for item in items:
# 模拟复杂计算
OS.delay_msec(100)
var processed_item = {
"id": item.id,
"name": item.name,
"value": item.value * 1.5
}
processed_items.append(processed_item)
print("[异步线程] 库存处理完成")
return processed_items,
_on_inventory_processed,
_on_inventory_error
)高级功能
任务管理
gdscript
# 获取活动异步任务数量
var active_tasks = bus.get_active_async_task_count()
print("活动异步任务: ", active_tasks)
# 处理完成的异步任务(必须在 _process 中调用)
func _process(_delta):
bus.process_async_tasks()
# 等待所有异步任务完成
bus.wait_all_async_tasks()
# 取消特定异步任务
var task_id = bus.emit_async("long_operation", [data])
bus.cancel_async_task(task_id)任务状态监控
gdscript
func _ready():
# 设置定时器监控异步任务状态
var timer = Timer.new()
timer.wait_time = 1.0
timer.timeout.connect(_monitor_async_tasks)
timer.autostart = true
add_child(timer)
func _monitor_async_tasks():
var active_count = bus.get_active_async_task_count()
if active_count > 5:
print("警告: 活动异步任务过多: ", active_count)错误处理
超时处理
gdscript
# 使用带错误回调的异步订阅
bus.subscribe_async_with_callbacks("network_request",
func(args):
var url = args[0]
# 模拟可能失败的操作
OS.delay_msec(2000)
if randf() < 0.3: # 30% 失败率
return null # 返回 null 表示失败
return "Success response",
func(result):
print("请求成功: ", result),
func(error):
print("请求失败: ", error)
)重试机制
gdscript
# 实现重试逻辑
func retry_async_operation(signal_name, args, max_retries=3):
var retry_count = 0
func attempt_operation():
bus.subscribe_async_with_callbacks(signal_name + "_retry",
func(op_args):
# 执行实际操作
return perform_operation(op_args[0]),
func(result):
print("操作成功")
cleanup_retry_subscription(signal_name + "_retry"),
func(error):
retry_count += 1
if retry_count < max_retries:
print("重试 ", retry_count, "/", max_retries)
attempt_operation()
else:
print("重试次数用尽,操作失败")
cleanup_retry_subscription(signal_name + "_retry")
)
bus.emit(signal_name + "_retry", [args])
attempt_operation()性能优化
批量处理
gdscript
# 将多个小任务合并为一个批量任务
var items_to_process = []
func add_item_to_queue(item):
items_to_process.append(item)
# 达到批量大小或定时处理
if items_to_process.size() >= 10:
process_batch()
func process_batch():
if items_to_process.size() > 0:
bus.emit_async("process_inventory_batch", [items_to_process.duplicate()])
items_to_process.clear()资源管理
gdscript
func _exit_tree():
# 等待所有异步任务完成
bus.wait_all_async_tasks()
# 或者取消特定任务
# bus.cancel_async_task(task_id)最佳实践
1. 合理使用异步
gdscript
# 适合异步的操作
- 文件 I/O
- 网络请求
- 复杂计算
- 大量数据处理
# 不适合异步的操作
- 简单状态更新
- UI 相关操作
- 需要立即响应的操作2. 错误处理
gdscript
func _on_async_complete(success, result):
if success:
handle_success(result)
else:
handle_error(result)
# 考虑重试或回退方案3. 资源管理
gdscript
func _exit_tree():
# 取消该对象的所有异步任务
bus.unsubscribe_all(self)调试和监控
异步任务监控
gdscript
func _ready():
# 启用调试模式
bus.set_debug_enabled(true)
func _process(_delta):
# 处理异步任务
bus.process_async_tasks()
# 定期检查任务状态
if Engine.get_frames_drawn() % 60 == 0: # 每秒检查一次
var active_tasks = bus.get_active_async_task_count()
if active_tasks > 10:
print("警告: 活动异步任务过多: ", active_tasks)示例:完整的异步保存系统
gdscript
# SaveManager.gd
extends Node
var bus
func _ready():
bus = SignalBus.get_singleton()
# 订阅异步保存信号
bus.subscribe_async_with_callbacks("save_game",
func(args):
var save_data = args[0]
var path = args[1]
print("[异步线程] 开始保存游戏...")
OS.delay_msec(2000) # 模拟保存时间
var file = FileAccess.open(path, FileAccess.WRITE)
if file:
file.store_var(save_data)
file.close()
return true
return false,
_on_save_complete,
_on_save_error
)
func save_game_async():
var save_data = prepare_save_data()
var save_path = "user://savegame.dat"
# 显示保存提示
show_saving_indicator()
# 异步保存
bus.emit_async("save_game", [save_data, save_path])
func _on_save_complete(success):
hide_saving_indicator()
if success:
show_message("游戏保存成功!")
update_save_timestamp()
else:
show_error("保存失败")
func _on_save_error(error):
hide_saving_indicator()
show_error("保存出错: " + str(error))
func _process(_delta):
# 必须在主线程处理异步任务
bus.process_async_tasks()
func _exit_tree():
# 取消所有未完成的保存任务
bus.unsubscribe_all(self)通过异步信号系统,你可以构建响应迅速、用户体验良好的游戏应用,同时保持代码的简洁和可维护性。