# 深入理解异步环境中的回调:从基础到实现
在现代编程中,回调机制为异步操作提供了极大的灵活性。本篇文章将深入探讨如何在异步环境中使用回调,以及如何编写自定义的异步回调处理器。
## 引言
本篇文章的目的是帮助读者理解和应用回调机制,特别是在异步编程环境中。我们将探讨如何通过扩展 `AsyncCallbackHandler` 来使用异步 API,并避免阻塞事件循环。
## 主要内容
### 什么是回调?
回调是指在特定事件发生时调用的函数。它们在异步编程中尤为重要,因为它们允许我们在操作完成后执行代码,而无需阻塞程序的其余部分。
### 自定义回调处理器
在使用异步 API 时,建议使用并扩展 `AsyncCallbackHandler`,以确保事件循环不被阻塞。例如,当使用同步回调处理器时,可能会遇到由于使用 `run_in_executor` 导致的线程安全问题。
### 版本兼容性问题
如果您使用的 Python 版本 <= 3.10,需要在某些情况下手动传播配置或回调,以确保回调能够正确传递给所有被调用的子程序。
## 代码示例
下面是一个使用 `langchain` 库的示例,其中包含同步和异步的回调处理器:
```python
import asyncio
from typing import Any, Dict, List
from langchain_anthropic import ChatAnthropic
from langchain_core.callbacks import AsyncCallbackHandler, BaseCallbackHandler
from langchain_core.messages import HumanMessage
from langchain_core.outputs import LLMResult
class MyCustomSyncHandler(BaseCallbackHandler):
def on_llm_new_token(self, token: str, **kwargs) -> None:
print(f"Sync handler being called in a `thread_pool_executor`: token: {token}")
class MyCustomAsyncHandler(AsyncCallbackHandler):
"""Async callback handler that can be used to handle callbacks from langchain."""
async def on_llm_start(self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any) -> None:
print("zzzz....")
await asyncio.sleep(0.3)
print("Hi! I just woke up. Your llm is starting")
async def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
print("zzzz....")
await asyncio.sleep(0.3)
print("Hi! I just woke up. Your llm is ending")
# 创建ChatAnthropic实例,并使用API代理服务提高访问稳定性
chat = ChatAnthropic(
model="claude-3-sonnet-20240229",
max_tokens=25,
streaming=True,
callbacks=[MyCustomSyncHandler(), MyCustomAsyncHandler()],
)
await chat.agenerate([[HumanMessage(content="Tell me a joke")]])
常见问题和解决方案
- 线程安全问题: 确保回调处理器是线程安全的,尤其在使用同步回调时。
- 回调传播: 特别是对于 Python <= 3.10,确保在必要时手动传播配置和回调。
总结和进一步学习资源
异步回调处理是提升程序性能和响应能力的重要工具。要深入了解和应用它,建议阅读以下资源:
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---