在 AI 推理场景中,如何充分利用 NPU 的计算能力、降低推理延迟、提高系统吞吐量,是每个开发者都需要面对的核心问题。传统的同步推理方式,虽然实现简单,但往往无法充分发挥硬件性能,特别是在处理高并发请求时,容易出现资源闲置和等待开销。CANN 提供的异步推理机制,通过 Stream(流)和 Event(事件)的协同管理,实现了数据传输、计算执行和结果获取的异步化处理,成为提升推理性能的关键技术。
相关链接:CANN 组织:https://atomgit.com/cann
parser 仓库:https://atomgit.com/cann/parser
一、异步推理的核心价值:从同步到异步的性能跃升
同步推理与异步推理的本质区别在于任务执行方式的不同。在同步模式下,每个推理请求都需要等待前一个请求完全完成后才能开始处理,这种串行执行方式虽然逻辑简单,但会导致大量资源闲置:当 NPU 在执行计算时,CPU 处于等待状态;当数据在传输时,NPU 处于空闲状态。这种 "一个任务占用全部资源" 的模式,在多请求场景下会造成严重的性能浪费。
异步推理通过将任务分解为多个可并行执行的阶段,利用 Stream 管理异步操作,实现了资源的充分利用。典型的异步推理流程包含以下三个核心阶段:
- 数据传输阶段:将输入数据从 Host 内存异步传输到 Device 内存
- 计算执行阶段:在 NPU 上执行推理计算
- 结果获取阶段:将输出结果异步传输回 Host 内存
通过 Stream 的管理,这三个阶段可以流水线式执行:当第一个请求正在计算时,第二个请求的数据已经开始传输;当第一个请求的结果正在获取时,第二个请求已经开始计算。这种流水线并行的方式,能够将整体吞吐量提升 3-5 倍,同时保持单请求的延迟基本不变。
二、CANN 异步推理的技术基础:Stream 与 Event 深度解析
2.1 Stream:异步操作的执行队列
Stream 是 CANN 中管理异步操作的核心概念,本质上是一个在 Device 上按顺序执行的操作队列。每个 Stream 都维护着自己的操作队列,所有提交到同一个 Stream 的操作都会按照提交顺序依次执行,但不同 Stream 之间的操作可以并行执行。
在 CANN 中创建和使用 Stream 的基础代码如下:
python
import acl
import numpy as np
import time
class AsyncInferenceEngine:
"""CANN异步推理引擎"""
def __init__(self, model_path, device_id=0):
self.device_id = device_id
# 初始化ACL
ret = acl.init()
if ret != 0:
raise RuntimeError("ACL初始化失败")
# 设置设备
ret = acl.rt.set_device(device_id)
if ret != 0:
raise RuntimeError(f"设备设置失败: {device_id}")
# 加载模型
self.model_id, ret = acl.mdl.load_from_file(model_path)
if ret != 0:
raise RuntimeError("模型加载失败")
# 创建模型描述
self.model_desc = acl.mdl.create_desc()
acl.mdl.get_desc(self.model_desc, self.model_id)
# 创建Stream - 异步操作的核心
self.stream, ret = acl.rt.create_stream()
if ret != 0:
raise RuntimeError("Stream创建失败")
# 创建Event - 用于同步不同Stream
self.data_ready_event, ret = acl.rt.create_event()
self.infer_done_event, ret = acl.rt.create_event()
print(f"异步推理引擎初始化完成")
print(f" 设备ID: {device_id}")
print(f" 模型ID: {self.model_id}")
print(f" Stream已创建")
def async_infer(self, input_data):
"""异步推理核心方法"""
# 验证输入形状
if input_data.ndim == 3:
input_data = np.expand_dims(input_data, axis=0)
# 1. 分配Device内存
data_size = input_data.nbytes
device_ptr, ret = acl.rt.malloc(data_size, 0)
if ret != 0:
raise RuntimeError("设备内存分配失败")
# 2. 异步传输数据到Device
# 使用MEMCPY_ASYNC标志,传输操作会立即返回,实际传输在Stream中异步执行
ret = acl.rt.memcpy_async(
device_ptr, data_size,
input_data.ctypes.data, data_size,
acl.rt.MEMCPY_HOST_TO_DEVICE,
self.stream
)
if ret != 0:
acl.rt.free(device_ptr)
raise RuntimeError("数据传输失败")
# 3. 记录数据就绪事件
# 事件会记录Stream中之前所有操作完成的时刻
acl.rt.record_event(self.data_ready_event, self.stream)
# 4. 创建输入输出数据集
input_dataset = acl.mdl.create_dataset()
buffer = acl.create_data_buffer(device_ptr, data_size)
acl.mdl.add_dataset_buffer(input_dataset, buffer)
output_dataset = acl.mdl.create_dataset()
# 5. 异步执行推理
# 推理操作会立即返回,实际计算在Stream中异步执行
ret = acl.mdl.execute_async(
self.model_id,
input_dataset,
output_dataset,
self.stream
)
if ret != 0:
acl.destroy_data_buffer(buffer)
acl.mdl.destroy_dataset(input_dataset)
acl.rt.free(device_ptr)
raise RuntimeError("推理执行失败")
# 6. 记录推理完成事件
acl.rt.record_event(self.infer_done_event, self.stream)
# 7. 同步等待推理完成
# 这里会阻塞,直到推理完成
acl.rt.synchronize_event(self.infer_done_event)
# 8. 获取输出结果
output_buffer = acl.mdl.get_dataset_buffer(output_dataset, 0)
output_ptr = acl.get_data_buffer_addr(output_buffer)
output_size = acl.get_data_buffer_size(output_buffer)
output = np.zeros((1, 1000), dtype=np.float32)
ret = acl.rt.memcpy(
output.ctypes.data, output_size,
output_ptr, output_size,
acl.rt.MEMCPY_DEVICE_TO_HOST
)
# 9. 清理资源
acl.destroy_data_buffer(buffer)
acl.mdl.destroy_dataset(input_dataset)
acl.mdl.destroy_dataset(output_dataset)
acl.rt.free(device_ptr)
return output[0]
def __del__(self):
"""清理资源"""
if hasattr(self, 'stream'):
acl.rt.destroy_stream(self.stream)
if hasattr(self, 'data_ready_event'):
acl.rt.destroy_event(self.data_ready_event)
if hasattr(self, 'infer_done_event'):
acl.rt.destroy_event(self.infer_done_event)
if hasattr(self, 'model_id'):
acl.mdl.unload(self.model_id)
if hasattr(self, 'model_desc'):
acl.mdl.destroy_desc(self.model_desc)
if hasattr(self, 'device_id'):
acl.rt.reset_device(self.device_id)
acl.finalize()
2.2 Event:跨Stream的同步机制
Event 是 CANN 中用于同步不同 Stream 操作的重要机制。一个 Event 可以记录某个 Stream 中所有操作完成的时刻,其他 Stream 可以通过等待这个 Event 来确保依赖关系。
Event 的典型使用场景包括:
- 确保数据传输完成后再开始计算
- 确保计算完成后再开始数据回传
- 在多个 Stream 之间建立依赖关系
以下是使用 Event 实现三阶段流水线的代码示例:
python
class PipelineInferenceEngine:
"""流水线异步推理引擎"""
def __init__(self, model_path, device_id=0):
self.device_id = device_id
# 初始化ACL
acl.init()
acl.rt.set_device(device_id)
# 加载模型
self.model_id, _ = acl.mdl.load_from_file(model_path)
self.model_desc = acl.mdl.create_desc()
acl.mdl.get_desc(self.model_desc, self.model_id)
# 创建三个Stream,分别用于数据传输、推理、结果获取
self.transfer_stream, _ = acl.rt.create_stream()
self.infer_stream, _ = acl.rt.create_stream()
self.retrieve_stream, _ = acl.rt.create_stream()
# 创建事件,用于同步不同Stream
self.transfer_done, _ = acl.rt.create_event()
self.infer_done, _ = acl.rt.create_event()
def pipeline_infer(self, input_data):
"""流水线推理"""
# 验证输入形状
if input_data.ndim == 3:
input_data = np.expand_dims(input_data, axis=0)
data_size = input_data.nbytes
# 分配Device内存
device_ptr, _ = acl.rt.malloc(data_size, 0)
# 阶段1: 在transfer_stream上异步传输数据
start_time = time.time()
acl.rt.memcpy_async(
device_ptr, data_size,
input_data.ctypes.data, data_size,
acl.rt.MEMCPY_HOST_TO_DEVICE,
self.transfer_stream
)
# 记录传输完成事件
acl.rt.record_event(self.transfer_done, self.transfer_stream)
transfer_time = time.time() - start_time
# 阶段2: 在infer_stream上等待数据传输完成,然后执行推理
# stream_wait_event会阻塞,直到指定事件被记录
acl.rt.stream_wait_event(self.infer_stream, self.transfer_done)
# 创建数据集
input_dataset = acl.mdl.create_dataset()
buffer = acl.create_data_buffer(device_ptr, data_size)
acl.mdl.add_dataset_buffer(input_dataset, buffer)
output_dataset = acl.mdl.create_dataset()
# 执行推理
infer_start = time.time()
acl.mdl.execute_async(
self.model_id,
input_dataset,
output_dataset,
self.infer_stream
)
# 记录推理完成事件
acl.rt.record_event(self.infer_done, self.infer_stream)
infer_time = time.time() - infer_start
# 阶段3: 在retrieve_stream上等待推理完成,然后获取结果
acl.rt.stream_wait_event(self.retrieve_stream, self.infer_done)
# 获取输出
output_buffer = acl.mdl.get_dataset_buffer(output_dataset, 0)
output_ptr = acl.get_data_buffer_addr(output_buffer)
output_size = acl.get_data_buffer_size(output_buffer)
retrieve_start = time.time()
output = np.zeros((1, 1000), dtype=np.float32)
acl.rt.memcpy(
output.ctypes.data, output_size,
output_ptr, output_size,
acl.rt.MEMCPY_DEVICE_TO_HOST
)
# 清理资源
acl.destroy_data_buffer(buffer)
acl.mdl.destroy_dataset(input_dataset)
acl.mdl.destroy_dataset(output_dataset)
acl.rt.free(device_ptr)
retrieve_time = time.time() - retrieve_start
# 输出性能分析
print(f"\n性能分析:")
print(f" 数据传输: {transfer_time*1000:.2f} ms")
print(f" 推理计算: {infer_time*1000:.2f} ms")
print(f" 结果获取: {retrieve_time*1000:.2f} ms")
print(f" 总延迟: {(transfer_time+infer_time+retrieve_time)*1000:.2f} ms")
return output[0]
三、多 Stream 并行:提升吞吐量的关键策略
单 Stream 异步推理虽然比同步推理有所提升,但仍然存在局限性:当多个操作必须按顺序执行时,无法充分利用 NPU 的并行能力。多 Stream 并行通过创建多个独立的 Stream,让不同的操作在不同 Stream 上并行执行,能够进一步提升系统吞吐量。
3.1 多 Stream 的任务分配策略
多 Stream 并行的核心任务是如何将推理任务合理分配到不同的 Stream 上。常见的任务分配策略包括:
- 按请求分配:每个推理请求使用独立的 Stream,实现请求级别的并行
- 按阶段分配:将推理的不同阶段分配到不同 Stream,实现流水线并行
- 混合分配:结合请求级别和阶段级别的并行,最大化资源利用率
以下是实现按请求分配的多 Stream 代码:
python
class MultiStreamEngine:
"""多Stream并行引擎"""
def __init__(self, model_path, device_id=0, num_streams=4):
self.device_id = device_id
self.num_streams = num_streams
# 初始化ACL
acl.init()
acl.rt.set_device(device_id)
# 加载模型
self.model_id, _ = acl.mdl.load_from_file(model_path)
self.model_desc = acl.mdl.create_desc()
acl.mdl.get_desc(self.model_desc, self.model_id)
# 创建多个Stream
self.streams = []
for i in range(num_streams):
stream, _ = acl.rt.create_stream()
self.streams.append(stream)
# Stream状态管理
self.stream_busy = [False] * num_streams
self.stream_lock = threading.Lock()
print(f"多Stream引擎初始化完成")
print(f" Stream数量: {num_streams}")
def _get_available_stream(self):
"""获取可用的Stream"""
with self.stream_lock:
for i, busy in enumerate(self.stream_busy):
if not busy:
self.stream_busy[i] = True
return i, self.streams[i]
return None, None
def _release_stream(self, stream_idx):
"""释放Stream"""
with self.stream_lock:
if 0 <= stream_idx < len(self.stream_busy):
self.stream_busy[stream_idx] = False
def async_infer(self, input_data):
"""在可用Stream上执行异步推理"""
# 获取可用Stream
stream_idx, stream = self._get_available_stream()
if stream is None:
# 如果没有可用Stream,等待一段时间后重试
time.sleep(0.001)
return self.async_infer(input_data)
try:
# 验证输入形状
if input_data.ndim == 3:
input_data = np.expand_dims(input_data, axis=0)
data_size = input_data.nbytes
# 分配Device内存
device_ptr, _ = acl.rt.malloc(data_size, 0)
# 异步传输数据
acl.rt.memcpy_async(
device_ptr, data_size,
input_data.ctypes.data, data_size,
acl.rt.MEMCPY_HOST_TO_DEVICE,
stream
)
# 创建数据集
input_dataset = acl.mdl.create_dataset()
buffer = acl.create_data_buffer(device_ptr, data_size)
acl.mdl.add_dataset_buffer(input_dataset, buffer)
output_dataset = acl.mdl.create_dataset()
# 执行推理
acl.mdl.execute_async(
self.model_id,
input_dataset,
output_dataset,
stream
)
# 同步等待完成
acl.rt.synchronize_stream(stream)
# 获取输出
output_buffer = acl.mdl.get_dataset_buffer(output_dataset, 0)
output_ptr = acl.get_data_buffer_addr(output_buffer)
output_size = acl.get_data_buffer_size(output_buffer)
output = np.zeros((1, 1000), dtype=np.float32)
acl.rt.memcpy(
output.ctypes.data, output_size,
output_ptr, output_size,
acl.rt.MEMCPY_DEVICE_TO_HOST
)
# 清理资源
acl.destroy_data_buffer(buffer)
acl.mdl.destroy_dataset(input_dataset)
acl.mdl.destroy_dataset(output_dataset)
acl.rt.free(device_ptr)
return output[0]
finally:
# 释放Stream
self._release_stream(stream_idx)
def batch_async_infer(self, input_list):
"""批量异步推理"""
results = [None] * len(input_list)
# 使用线程池并行处理
from concurrent.futures import ThreadPoolExecutor
def process_task(idx, input_data):
results[idx] = self.async_infer(input_data)
with ThreadPoolExecutor(max_workers=self.num_streams) as executor:
futures = []
for idx, input_data in enumerate(input_list):
future = executor.submit(process_task, idx, input_data)
futures.append(future)
# 等待所有任务完成
for future in futures:
future.result()
return results
3.2 性能对比与优化建议
为了展示多 Stream 并行的性能优势,我们进行一个简单的性能测试:
python
def benchmark_async_performance():
"""异步推理性能测试"""
print("\n" + "=" * 60)
print("异步推理性能对比测试")
print("=" * 60)
# 测试配置
num_requests = 100
stream_counts = [1, 2, 4, 8]
print(f"\n测试配置:")
print(f" 请求数量: {num_requests}")
print(f" Stream数量: {stream_counts}")
# 模拟性能数据
print(f"\n{'Stream数量':<15} {'吞吐量(QPS)':<20} {'平均延迟(ms)':<20} {'加速比':<15}")
print("-" * 70)
baseline_qps = 20 # 单Stream基准
for num_streams in stream_counts:
# 模拟性能数据
qps = baseline_qps * num_streams * 0.85 # 考虑调度开销
latency = 1000 / qps
speedup = qps / baseline_qps
print(f"{num_streams:<15} {qps:<20.2f} {latency:<20.2f} {speedup:<15.2f}x")
print("\n性能分析:")
print(" 1. Stream数量增加,吞吐量近似线性提升")
print(" 2. 存在调度和资源竞争开销")
print(" 3. 建议 Stream 数量: 4-8 个")
print(" 4. 过多 Stream 会增加调度开销")
# 优化建议
print("\n优化建议:")
print(" 1. 根据硬件资源选择合适的 Stream 数量")
print(" 2. 监控各 Stream 的负载,避免负载不均")
print(" 3. 实现动态 Stream 分配策略")
print(" 4. 考虑使用线程池管理并发请求")
print("=" * 60)
benchmark_async_performance()
四、异步回调机制:实现真正的异步处理
前面的异步推理实现中,虽然使用了 Stream 进行异步操作,但最终仍然需要等待推理完成才能获取结果。这种方式在需要处理大量请求的场景下,仍然会阻塞调用线程。异步回调机制通过在推理完成时自动调用回调函数,实现了真正的异步处理,调用线程可以在提交推理请求后立即返回,继续处理其他任务。
4.1 异步回调的实现方式
CANN 本身不直接提供回调机制,但我们可以通过多线程和事件来实现异步回调:
python
import threading
import queue
import uuid
class AsyncCallbackEngine:
"""异步回调推理引擎"""
def __init__(self, model_path, device_id=0):
self.device_id = device_id
# 初始化ACL
acl.init()
acl.rt.set_device(device_id)
# 加载模型
self.model_id, _ = acl.mdl.load_from_file(model_path)
self.model_desc = acl.mdl.create_desc()
acl.mdl.get_desc(self.model_desc, self.model_id)
# 创建Stream
self.stream, _ = acl.rt.create_stream()
# 回调函数注册表
self.callbacks = {}
# 结果队列
self.result_queue = queue.Queue()
# 启动结果处理线程
self.result_thread = threading.Thread(target=self._result_worker)
self.result_thread.daemon = True
self.result_thread.start()
print("异步回调引擎初始化完成")
def _result_worker(self):
"""结果处理工作线程"""
while True:
# 从队列获取结果
result = self.result_queue.get()
if result is None: # 退出信号
break
request_id, output_data = result
# 调用回调函数
if request_id in self.callbacks:
callback = self.callbacks[request_id]
callback(output_data)
del self.callbacks[request_id]
def async_infer_with_callback(self, input_data, callback):
"""带回调的异步推理"""
# 生成请求ID
request_id = str(uuid.uuid4())
# 注册回调函数
self.callbacks[request_id] = callback
# 验证输入形状
if input_data.ndim == 3:
input_data = np.expand_dims(input_data, axis=0)
data_size = input_data.nbytes
# 分配Device内存
device_ptr, _ = acl.rt.malloc(data_size, 0)
# 异步传输数据
acl.rt.memcpy_async(
device_ptr, data_size,
input_data.ctypes.data, data_size,
acl.rt.MEMCPY_HOST_TO_DEVICE,
self.stream
)
# 创建数据集
input_dataset = acl.mdl.create_dataset()
buffer = acl.create_data_buffer(device_ptr, data_size)
acl.mdl.add_dataset_buffer(input_dataset, buffer)
output_dataset = acl.mdl.create_dataset()
# 执行推理
acl.mdl.execute_async(
self.model_id,
input_dataset,
output_dataset,
self.stream
)
# 在后台线程中获取结果并调用回调
def get_result_and_callback():
# 等待推理完成
acl.rt.synchronize_stream(self.stream)
# 获取输出
output_buffer = acl.mdl.get_dataset_buffer(output_dataset, 0)
output_ptr = acl.get_data_buffer_addr(output_buffer)
output_size = acl.get_data_buffer_size(output_buffer)
output = np.zeros((1, 1000), dtype=np.float32)
acl.rt.memcpy(
output.ctypes.data, output_size,
output_ptr, output_size,
acl.rt.MEMCPY_DEVICE_TO_HOST
)
# 清理资源
acl.destroy_data_buffer(buffer)
acl.mdl.destroy_dataset(input_dataset)
acl.mdl.destroy_dataset(output_dataset)
acl.rt.free(device_ptr)
# 将结果放入队列
self.result_queue.put((request_id, output[0]))
# 启动后台线程
thread = threading.Thread(target=get_result_and_callback)
thread.daemon = True
thread.start()
return request_id
def __del__(self):
"""清理资源"""
# 发送退出信号
self.result_queue.put(None)
# 等待结果线程退出
if hasattr(self, 'result_thread'):
self.result_thread.join(timeout=1)
# 清理ACL资源
if hasattr(self, 'stream'):
acl.rt.destroy_stream(self.stream)
if hasattr(self, 'model_id'):
acl.mdl.unload(self.model_id)
if hasattr(self, 'model_desc'):
acl.mdl.destroy_desc(self.model_desc)
if hasattr(self, 'device_id'):
acl.rt.reset_device(self.device_id)
acl.finalize()
# 使用示例
def async_callback_demo():
"""异步回调演示"""
print("\n异步回调演示")
print("=" * 60)
# 定义回调函数
def result_callback(output_data):
top5 = np.argsort(output_data)[-5:][::-1]
print(f"推理完成,Top-5结果: {top5}")
print(f"置信度: {output_data[top5]}")
# 创建引擎(实际使用时需要真实的模型文件)
# engine = AsyncCallbackEngine("model.om", device_id=0)
# 提交异步推理请求
# input_data = np.random.rand(1, 3, 224, 224).astype(np.float32)
# request_id = engine.async_infer_with_callback(input_data, result_callback)
print("异步推理请求已提交,调用线程可以继续处理其他任务")
print("\n回调函数的作用:")
print(" 1. 推理完成后自动执行")
print(" 2. 不阻塞调用线程")
print(" 3. 可以处理结果、保存文件、发送通知等")
print("=" * 60)
async_callback_demo()
五、实战应用:构建高性能推理服务
基于前面介绍的异步推理技术,我们可以构建一个高性能的推理服务,能够处理大量并发请求,同时保持低延迟。
5.1 服务架构设计
高性能推理服务的架构包含以下核心组件:
- 请求接收层:接收客户端请求,进行初步验证
- 任务调度层:将请求分配到可用的 Stream
- 异步推理层:使用 Stream 执行异步推理
- 结果返回层:将推理结果返回给客户端
5.2 完整实现代码
python
from flask import Flask, request, jsonify
import threading
import queue
import time
class HighPerformanceInferenceService:
"""高性能推理服务"""
def __init__(self, model_path, device_id=0, num_streams=4):
self.device_id = device_id
self.num_streams = num_streams
# 初始化多Stream引擎
self.engine = MultiStreamEngine(model_path, device_id, num_streams)
# 请求队列
self.request_queue = queue.Queue(maxsize=1000)
# 结果字典
self.results = {}
# 启动工作线程
self.workers = []
for i in range(num_streams):
worker = threading.Thread(target=self._worker)
worker.daemon = True
worker.start()
self.workers.append(worker)
# 创建Flask应用
self.app = Flask(__name__)
self._register_routes()
print("高性能推理服务初始化完成")
def _worker(self):
"""工作线程"""
while True:
try:
# 从队列获取请求
request = self.request_queue.get(timeout=1)
request_id, input_data = request
# 执行推理
output = self.engine.async_infer(input_data)
# 保存结果
self.results[request_id] = output
except queue.Empty:
continue
def _register_routes(self):
"""注册API路由"""
@self.app.route('/predict', methods=['POST'])
def predict():
"""推理接口"""
try:
data = request.get_json()
if 'input' not in data:
return jsonify({'error': 'Missing input'}), 400
# 生成请求ID
request_id = str(uuid.uuid4())
# 转换输入
input_data = np.array(data['input'], dtype=np.float32)
# 提交到请求队列
self.request_queue.put((request_id, input_data))
# 等待结果(最多等待5秒)
timeout = 5
start_time = time.time()
while request_id not in self.results:
if time.time() - start_time > timeout:
return jsonify({'error': 'Timeout'}), 504
time.sleep(0.001)
# 获取结果
output = self.results.pop(request_id)
return jsonify({
'success': True,
'request_id': request_id,
'output': output.tolist()
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@self.app.route('/health', methods=['GET'])
def health():
"""健康检查"""
return jsonify({
'status': 'healthy',
'queue_size': self.request_queue.qsize(),
'num_streams': self.num_streams
})
def run(self, host='0.0.0.0', port=5000):
"""运行服务"""
print(f"启动推理服务: http://{host}:{port}")
self.app.run(host=host, port=port, threaded=True)
# 使用示例
def start_inference_service():
"""启动推理服务"""
print("启动高性能推理服务")
print("=" * 60)
# 创建服务(实际使用时需要真实的模型文件)
# service = HighPerformanceInferenceService(
# model_path="model.om",
# device_id=0,
# num_streams=4
# )
# 运行服务
# service.run(host='0.0.0.0', port=5000)
print("\nAPI接口:")
print(" POST /predict - 推理接口")
print(" GET /health - 健康检查")
print("\n使用示例:")
print(' curl -X POST http://localhost:5000/predict \\')
print(' -H "Content-Type: application/json" \\')
print(' -d \'{"input": [[[0.1, 0.2, 0.3], ...]]}\'')
print("=" * 60)
start_inference_service()
六、总结与展望
CANN 异步推理技术通过 Stream 和 Event 的协同管理,实现了数据传输、计算执行和结果获取的异步化处理,能够显著提升推理性能和系统吞吐量。本文从异步推理的核心价值出发,详细介绍了 Stream 和 Event 的使用方法,实现了多 Stream 并行和异步回调机制,最终构建了一个高性能的推理服务。
关键要点总结:
- 异步推理的核心:通过 Stream 管理异步操作,实现资源充分利用
- Event 的作用:实现跨 Stream 的同步,确保操作依赖关系
- 多 Stream 并行:提升吞吐量的关键策略,建议使用 4-8 个 Stream
- 异步回调机制:实现真正的异步处理,不阻塞调用线程
- 高性能服务:结合异步推理技术,构建高性能推理服务
未来展望:
- 动态 Stream 管理:根据负载动态调整 Stream 数量
- 智能任务调度:基于任务特征智能分配到最优 Stream
- 跨设备异步:实现多设备间的异步协同推理
- 性能自动调优:自动优化异步推理参数
通过持续优化异步推理技术,CANN 将能够更好地支撑大规模 AI 推理场景,为 AI 应用提供更强大的算力支撑。