探索异步环境中的回调:实用指南

93 阅读2分钟
# 探索异步环境中的回调:实用指南

## 引言
随着异步编程在现代应用开发中的应用越来越广泛,理解如何在异步环境中使用回调变得至关重要。回调机制不仅可以提高应用程序的响应性,还可以有效管理长时间运行的任务。本文旨在帮助您掌握在异步环境中使用回调的方法,包括创建自定义的回调处理程序。

## 主要内容

### 为什么选择异步回调?
异步回调允许您在不同的事件发生时执行代码,而不会阻塞主线程。例如,在处理大量I/O操作时,异步回调可以显著改善程序的性能。

### 自定义异步回调处理程序
在异步编程中,我们可以通过继承并扩展 `AsyncCallbackHandler` 来创建自定义的异步回调处理程序。这有助于在大型系统中保持组织良好且模块化的代码结构。

### 注意事项
1. **线程安全**:在异步环境中使用同步回调处理程序时,尤其是在 `thread_pool_executor` 中运行时,一定要确保其线程安全。
2. **Python版本**:对于 `python<=3.10`,特别要注意回调的传播,否则在 `RunnableLambda``RunnableGenerator` 等内调用其他可运行对象时,可能会丢失回调。

## 代码示例

以下代码展示了如何在异步环境中使用自定义回调处理程序:

```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:
        """Run when chain starts running."""
        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:
        """Run when chain ends running."""
        print("zzzz....")
        await asyncio.sleep(0.3)
        print("Hi! I just woke up. Your llm is ending")


# 使用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")]])

常见问题和解决方案

  1. 回调不被调用:确保回调处理程序已经正确注册,并注意Python版本对回调传播的影响。
  2. 性能问题:在处理大量回调时,异步方法应始终使用 await 关键字以非阻塞方式执行任务。

总结和进一步学习资源

掌握异步回调不仅能改善程序性能,还能增强代码的可维护性。对于进一步的学习,建议参阅以下资源:

参考资料

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---