阳江市网站建设_网站建设公司_Oracle_seo优化
2025/12/19 23:17:42 网站建设 项目流程

目录
  • 进程与线程
  • 同步与异步,阻塞与非阻塞
  • asyncio

进程与线程

  • 在我们在终端用python命令启动一个程序的时候,就是创建了一个python进程
  • 进程包含一个或者多个线程,以及其他各种资源。
    • 真正执行代码的是线程
    • 可以把进程想象成一个公司,线程就是这个公司里面的员工。公司除了员工,当然还有其他很多东西。
    • 一个进程至少有一个线程,这个线程叫做主线程
      • 如果程序不包含threading库等,那么这个进程一般只有一个线程,就是主线程
  • 一个CPU核心在同一时间只能执行一个线程
    • 超线程也是这样的,超线程只是用了更高级的切换线程的方式
    • 一个进程的线程可以在不同的CPU核心中被执行,哪个核心有空就在哪个核心执行
    • 所以其实进程数目不是根本因素,线程数目才是根本因素。看CPU是否有空闲/利用率是否高,就看其是否一直在执行线程

同步与异步,阻塞与非阻塞

老张爱喝茶,废话不说,煮开水。 出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。 1 老张把水壶放到火上,立等水开。(同步阻塞) 老张觉得自己有点傻 2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞) 老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。 3 老张把响水壶放到火上,立等水开。(异步阻塞) 老张觉得这样傻等意义不大 4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞) 老张觉得自己聪明了。

所谓同步异步,只是对于水壶而言。 普通水壶,同步;响水壶,异步。 虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。 同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。

所谓阻塞非阻塞,仅仅对于老张而言。 立等的老张,阻塞;看电视的老张,非阻塞。 情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。

这个例子中,老张相当于线程,水壶相当于IO请求,所以就是说同步异步就是指请求是否通知线程(关注的是消息通知机制),阻塞非阻塞就是指线程是否继续执行(关注的是调用者(线程)在等待结果时的状态)

asyncio

  • 在函数前加上async可以把函数变成协程
    • 调用协程不会执行函数,只会得到一个协程对象
    • 协程对象的执行需要通过asyncio.create_task()asyncio.gather()
  • asyncio.run() 的作用是:启动异步程序,运行一个顶级协程,并在结束后自动关闭事件循环
  • asyncio.create_task()的作用是把协程包装成一个 Task 并立即调度到事件循环中并发执行,从而让它“后台”运行,而不必等待它完成才能继续往下走
  • asyncio.gather()的作用是并发启动多个协程,等它们全部完成,然后把所有返回值按顺序收集成一个列表返回
  • await如果跟的是非IO语句,意义不大
  • asyncio库不会创建其他进程或者线程
    • 创建进程是multiprocessing
    • 创建线程是threading
    • asyncio库仍然是单线程执行,只不过不同的Task轮流执行

下面是一些具体的例子:

  • import asyncio
    from openai import AsyncOpenAIclient = AsyncOpenAI(api_key="sk-1234",base_url="http://0.0.0.0:4000"
    )async def chat(message: str) -> str:"""单个异步请求"""response = await client.chat.completions.create(model="my-model",messages=[{"role": "user", "content": message}])return response.choices[0].message.contentasync def main():# 定义多个独立的请求messages = ["What LLM are you?","Could you please tell 1+1 =?","I want to make friends with you.","Tell me a joke.","What is Python?",]# 使用 asyncio.gather 并发执行所有请求tasks = [chat(msg) for msg in messages]results = await asyncio.gather(*tasks)for msg, result in zip(messages, results):print(f"Q: {msg}\nA: {result}\n")# 运行
    asyncio.run(main())
    
    • 线程一直执行到tasks = [chat(msg) for msg in messages],然后这个语句创建了若干协程对象
    • results = await asyncio.gather(*tasks)
      • awaitmain函数挂起,意思是等到asyncio.gather(*tasks)执行结束之后再继续执行下面的代码
      • asyncio.gather(*tasks)会把这些协程对象封装成 Task(如果还没封装的话),并注册到事件循环中
        • 同一时刻线程只能够执行一个Task
        • 当线程执行到某个Task的await client.chat.completions.create的时候,await会将当前Task挂起,控制权交还给事件循环,事件循环会查看“还有谁准备好了?”,然后让线程去执行下一个 Task
        • 最后所有协程对象执行都完毕了之后,将所有协程对象的执行结果按序放到results
  • import asyncioasync def chat(msg: str) -> str:print(f"开始处理: {msg}")await asyncio.sleep(1)  # 模拟网络请求print(f"完成处理: {msg}")return f"回复: {msg}"async def main():messages = ["A", "B", "C"]print("=== 串行执行 ===")for msg in messages:result = await chat(msg)print(result)asyncio.run(main())
    
    • 线程执行到result = await chat(msg)的时候,awaitmain挂起,线程去继续执行chat
    • 线程执行到await asyncio.sleep(1)的时候,会将chat挂起
    • 所以这个代码实际上线程是有空闲的(阻塞),不能实现异步IO

可以使用multiprocessing库开多个进程,每个进程里面使用asyncio库进行异步IO以最大化利用CPU资源

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询