当前位置: 首页 > news >正文

Python 多任务编程:进程、线程、协程全解

这里写目录标题

  • 前言
  • 一、python多任务概念
    • 1.1 什么是多任务,作用是什么
    • 1.2 多任务实现方式
      • 进程
      • 线程
      • 协程
    • 1.3 任务分类
      • CPU 密集型
      • I/O 密集型
    • 1.4 GIL 全局解释器锁
  • 二、Python 进程详解
    • 2.1 进程基础概念、实现与参数传递
    • 2.2 进程启动的底层原理与重要注意事项
    • 2.3 进程间通信(Queue)与底层原理
  • 三、Python 线程详解
    • 3.1 线程基础:概念、实现与传参
    • 3.2 线程核心注意事项(无序、守护、共享变量及安全问题)
    • 3.3 互斥锁与死锁
  • 四、线程池
    • 4.1 线程池概述:是什么,为什么用?
    • 4.2 Python 中的线程池实现
      • 4.2.1 创建线程池
      • 4.2.2 提交任务的两种方式
      • 4.2.3 获取结果、异常与回调
      • 4.2.4 关闭线程池
    • 4.3 深入原理:队列 + 工作线程模型
      • 4.4 完整示例:并发下载网页(I/O 密集型)
  • 五、python协程详解
    • 5.1 协程基础概念
    • 5.2 协程核心三要素
    • 5.3 协程实现与并发实战
      • 5.3.1 async 和 await协程核心语法规则
        • async 关键字作用
        • await 关键字使用约束与核心作用
      • 5.3.2 基础示例:await 自动封装协程对象
      • 5.3.3 并发实战:手动创建 `Task + asyncio.gather`
    • 5.4 协程底层调度原理、使用注意事项及异步本质
      • 5.4.1 协程底层调度原理
      • 5.4.2 协程为什么是异步的实现方式?体现在哪里
  • 六、进程 vs 线程vs 协程:核心对比

前言

在 Python 开发中,多任务编程是提升程序执行效率、充分利用 CPU 资源的核心手段,而进程、线程、协程是实现多任务的方式。

一、python多任务概念

1.1 什么是多任务,作用是什么

  1. 什么是多任务
    多任务指同一时间内执行多个任务(用户感官上的同时),比如电脑同时运行微 信、浏览器、IDE,就是典型的多任务场景。

  2. 多任务的作用
    充分利用 CPU 资源,避免单任务阻塞导致的效率低下,大幅提升程序运行速度。

  3. 多任务核心:并发 vs 并行

    • 并发:任务数 > CPU 核心数,操作系统交替执行任务(单核 CPU 必为并发),因 CPU 速度极快,感官上是同时运行。
    • 并行:任务数 ≤ CPU 核心数,多个 CPU 核心真正同时执行任务,效率更高。

1.2 多任务实现方式

进程

进程是操作系统资源分配的最小单位,每个进程拥有独立的内存空间和系统资源。多进程可以实现真正的并行(利用多核 CPU),但创建和切换开销较大,进程间通信也相对复杂。在 Python 中,multiprocessing模块用于实现多进程,适合 CPU 密集型任务。

线程

线程是操作系统调度的最小执行单元,同一进程内的多个线程共享内存空间,因此创建和切换开销较小,通信方便。但由于 Python 的 GIL(全局解释器锁),多线程无法实现真正的并行,仅能并发执行,适合 I/O 密集型任务。threading 模块提供了线程支持。

协程

协程是用户态的轻量级任务,完全由程序自身控制切换(如 async/await),无需操作系统参与,因此切换开销极低,单线程内可轻松运行数万甚至数十万个协程。协程不存在锁竞争问题,非常适合高并发的 I/O 场景。Python 的 asyncio 是协程编程的主流方案。

1.3 任务分类

CPU 密集型

任务主要消耗 CPU 计算资源(如循环计算、图像处理、模型训练),提升效率的关键是充分利用多核并行,适合采用多进程。

I/O 密集型

任务主要花费时间在等待输入输出(如文件读写、网络请求、数据库查询),提升效率的关键是减少阻塞等待,适合采用多线程或协程。

1.4 GIL 全局解释器锁

  1. GIL(Global Interpreter Lock,全局解释器锁)是 CPython 解释器中的一个互斥锁,它确保同一时刻只有一个线程执行 Python 字节码。

  2. 这意味着即使有多个 CPU 核心,python多线程也无法实现并行执行字节码,只能是并发。

  3. 需要说明的是,线程内部执行分为用户态和内核态,内核态就是当字节码执行到需要操作系统服务时(如打开文件、发送网络数据、创建线程),解释器会调用 C 库函数,最终触发系统调用,线程执行从用户态切换到内核态。

  4. 在进入内核态、且系统调用已经发起之后,CPython 解释器会主动释放 GIL,让其他等待中的线程有机会获取 GIL 并执行字节码。与此同时,当前线程继续在内核态运行操作系统代码;若该操作需要等待外部数据(如网络响应尚未到达),操作系统会将该线程挂起(阻塞),并让出 CPU 时间片,直到数据就绪后被重新唤醒。

  5. 因此,在python中,执行CPU密集型任务,适合用多进程,在执行IO密集型任务时,适合多线程,GIL对IO密集型任务的影响比较小。

二、Python 进程详解

2.1 进程基础概念、实现与参数传递

进程是操作系统资源分配的最小单位,一个运行的程序(如 Python 脚本)就是一个进程,每个进程拥有独立的内存空间和系统资源。进程内至少有一个主线程,也可以创建多个子线程。多进程即通过主进程创建子进程,实现多任务的并行或并发。

实现步骤(multiprocessing 模块)

  1. import multiprocessing
  2. 创建进程对象:p = multiprocessing.Process(target=任务函数, args/kwargs, name='进程名')
  3. 启动子进程:p.start()

参数传递支持元组和字典两种方式

p1=multiprocessing.Process(target=coding,args=(3,"小明"))# 元组传参p2=multiprocessing.Process(target=music,kwargs={"count":2,"name":"小明"})# 字典传参

获取进程编号(用于管理和调试)

  • 当前进程 ID:os.getpid() 或 multiprocessing.current_process().pid
  • 父进程 ID:os.getppid()

2.2 进程启动的底层原理与重要注意事项

启动原理:

Windows(默认 spawn 模式)
调用Process.start()会调用系统 API 生成全新子进程,启动独立 Python 解释器,执行python -c加载spawn_main入口脚本。父进程通过管道序列化传递目标函数与参数,子进程通过该脚本读取数据后导入当前脚本,执行指定任务。
Linux/macOS(默认 fork 模式)
底层直接调用系统fork()复制父进程内存空间,不新建解释器,无需执行额外 python 命令。子进程拷贝父进程运行状态后,清理多余资源,直接运行目标函数,不会完整重新加载脚本。
if__name__ == '__main__'作用
两种模式下子进程都会执行脚本顶层代码。若创建进程的代码未放入该判断块,spawn 模式会反复新建解释器递归创建进程;fork 模式也会持续复制子进程,最终出现无限创建进程、程序卡死的问题,因此进程实例化代码必须写在此分支内。

三大注意事项:

  1. 进程间不共享全局变量:子进程是主进程的资源副本,同名全局变量互不影响。
  2. 主进程默认等待所有子进程结束:会等子进程执行完毕再退出。
  3. 让主进程不等待子进程的方法:
    • 守护进程(推荐):p.daemon = True,主进程退出时子进程直接销毁。
    • 手动终止(不推荐):p.terminate(),易产生僵尸进程,无法释放资源。

2.3 进程间通信(Queue)与底层原理

由于进程内存隔离,无法像线程那样共享全局变量,需要通过multiprocessing.Queue实现数据传递。

frommultiprocessingimportProcess,Queuedefwrite(q):foriin["a","b","c"]:q.put(i)defread(q):whilenotq.empty():print(q.get())if__name__=='__main__':q=Queue()p1=Process(target=write,args=(q,))p2=Process(target=read,args=(q,))p1.start()p1.join()# 等待写进程结束p2.start()

底层原理multiprocessing.Queue内部基于操作系统的管道(或消息队列)实现。当进程 A 放入数据时,数据先被 pickle 序列化 成字节流,然后拷贝到操作系统内核空间的一块缓冲区;进程 B 取出数据时,内核将这份数据拷贝到进程 B 的内存中,再反序列化还原为对象。整个过程两个进程无法直接访问对方内存,全靠操作系统充当可靠的中介。

关于锁机制:虽然两个进程拥有各自内存中的 Queue 实例,但这些实例内部的_reader、_writer(管道文件描述符)以及_lock(跨进程锁)都指向操作系统中相同的内核对象(共享资源)。_lock是为了保护对管道缓冲区的并发访问,防止写入数据混乱。实际上 Queue 内部不止一把锁,还包括用于同步读取和写入的条件变量等,但核心思想就是:跨进程共享的资源必须通过系统级的锁来保证原子操作。

进程A(生产者)操作系统内核 进程B(消费者)|||1. put(obj)||- 获取锁(Lock)||- pick序列化 obj ->bytes||- 把bytes放入内部缓冲区|||||2. 后台线程运行||- 从缓冲区取出bytes||- 调用 write(pipe_fd, bytes)--->[管道缓冲区]|- 释放锁|||||||数据准备好||||||3. get()进程B被唤醒||- 获取锁||- 调用 read(pipe_fd)<---- 读数据 ,反序列化,释放锁||- 返回 obj

三、Python 线程详解

3.1 线程基础:概念、实现与传参

线程是 CPU 调度的最小单位,依附于进程存在。一个进程默认有一个主线程,可创建多个子线程,线程间共享进程的所有资源。多线程的资源开销远小于进程,适合 I/O 密集型任务。

实现步骤(threading 模块)

  1. import threading
  2. 创建线程对象:t = threading.Thread(target=任务函数, args/kwargs)
  3. 启动线程:t.start()

传参方式与进程完全相同,支持元组args=(3, "小红")和字典kwargs

3.2 线程核心注意事项(无序、守护、共享变量及安全问题)

  1. 线程执行无序:由 CPU 调度决定,与创建顺序无关,多次运行结果可能不同。

  2. 主线程默认等待子线程结束:可设置守护线程让主线程退出时销毁子线程:

    t=threading.Thread(target=work,daemon=True)# 方法1t.setDaemon(True)# 方法2
  3. 线程间共享全局变量:这是线程的核心优势,无需额外通信机制。

  4. 共享变量导致数据安全问题:多线程同时修改同一全局变量会产生资源竞争,导致计算结果错误。

3.3 互斥锁与死锁

互斥锁:保证同一时刻只有一个线程操作共享数据。步骤:创建锁 →acquire()上锁 →release()解锁。

importthreading g_num=0mutex=threading.Lock()def sum_num(): global g_num mutex.acquire()foriinrange(1000000): g_num+=1mutex.release()print(f"结果:{g_num}")t1=threading.Thread(target=sum_num)t2=threading.Thread(target=sum_num)t1.start();t2.start()

死锁问题:多个线程互相等待对方释放锁,导致程序卡死。常见原因:上锁后未释放、嵌套锁顺序不当。解决方法:保证锁的成对释放,避免嵌套锁,或使用 with 语句自动释放。

lock1=threading.Lock()lock2=threading.Lock()deffunc1():lock1.acquire()time.sleep(0.1)lock2.acquire()# 等待 lock2,但 lock2 可能被 func2 持有lock2.release()lock1.release()deffunc2():lock2.acquire()time.sleep(0.1)lock1.acquire()# 等待 lock1,但 lock1 被 func1 持有lock1.release()lock2.release()

四、线程池

4.1 线程池概述:是什么,为什么用?

  1. 什么是线程池
    线程池是一种 池化技术:预先创建一组可复用的线程,任务到来时分配给空闲线程执行,执行完后线程不销毁,而是等待下一个任务。

  2. 为什么需要线程池

    • 降低资源消耗:复用已存在的线程,减少频繁创建/销毁的开销。
    • 提高响应速度:任务到达时免去线程创建时间。
    • 便于统一管理:控制最大并发数,避免线程过多导致系统崩溃。
  3. 线程池 vs. 手动创建线程

    对比项手动创建线程线程池
    创建/销毁开销高,每个任务都要创建和销毁线程低,线程复用
    资源控制难以控制最大线程数可以设置最大线程数
    代码复杂度需要自行管理线程生命周期和异常简洁,只需提交任务

4.2 Python 中的线程池实现

python中主要使用concurrent.futures.ThreadPoolExecutor类实现线程池的创建和使用

4.2.1 创建线程池

fromconcurrent.futuresimportThreadPoolExecutor# 默认线程数:min(32, CPU核心数+4)executor=ThreadPoolExecutor()# 自定义最大线程数(常用)executor=ThreadPoolExecutor(max_workers=5)# 还可以指定线程名前缀、初始线程(Python 3.8+)executor=ThreadPoolExecutor(max_workers=5,thread_name_prefix="MyPool")

核心参数:

  • max_workers:线程池中最多同时运行的线程数。并非越多越好,建议根据 IO 密集型任务 的性质设置适当值(如 CPU 核心数 * 5 或更高)。
  • thread_name_prefix:为线程池中的线程命名,方便调试。

4.2.2 提交任务的两种方式

  1. submit(fn, *args, **kwargs)—— 提交单个任务

    future=executor.submit(print,"Hello")# future 是一个 Future 对象,代表异步操作的句柄
  2. map(func, *iterables, timeout=None)—— 批量提交

    defsquare(n):returnn*nwithThreadPoolExecutor()asexecutor:results=executor.map(square,[1,2,3,4,5])forrinresults:print(r)# 输出顺序与输入顺序一致

4.2.3 获取结果、异常与回调

  1. Future.result(timeout=None):阻塞等待结果,可设置超时,任务异常时此处会抛出。

  2. Future.done() / running() / cancelled()等用于状态查询。

  3. add_done_callback(fn):任务完成后自动调用回调函数(在任务线程中执行,注意线程安全)。

    defcallback(future):print(f"结果:{future.result()}")future=executor.submit(pow,2,10)future.add_done_callback(callback)

4.2.4 关闭线程池

# 方法一:等待所有任务完成,并禁止新任务executor.shutdown(wait=True)# wait=True 为默认,阻塞直到全部完成# 方法二:使用上下文管理器(推荐)withThreadPoolExecutor(max_workers=5)asexecutor:executor.submit(func,arg)# 离开 with 块时自动调用 shutdown(wait=True)

4.3 深入原理:队列 + 工作线程模型

ThreadPoolExecutor的核心是一个生产者‑消费者模型:

  • 一个任务队列(queue.Queue):主线程通过submit()将任务(包装成(fn, args, kwargs, future))放入队列。

  • 一组工作线程:线程池在初始化时不会立即创建所有线程,而是懒创建——当提交第一个任务时,如果当前线程数不足max_workers,就创建新线程;每个工作线程不断从队列中取任务执行,执行完后继续取下一个,永不退出(除非收到关闭信号)。

  • 线程池里的线程默认都是守护线程,关闭线程池时可以通过wait参数指定关闭线程池的行为,是等所有线程都完成还是让守护线程生效。

    classThreadPoolExecutor:def__init__(self,max_workers):self._work_queue=queue.Queue()self._threads=set()self._max_workers=max_workers self._shutdown=Falsedefsubmit(self,fn,*args,**kwargs):ifself._shutdown:raiseRuntimeError('cannot schedule new futures')f=Future()self._work_queue.put((fn,args,kwargs,f))# 懒创建线程iflen(self._threads)<self._max_workers:t=threading.Thread(target=self._worker)t.daemon=Trueself._threads.add(t)t.start()returnfdef_worker(self):whileTrue:item=self._work_queue.get()ifitemisNone:# 毒丸信号breakfn,args,kwargs,future=itemtry:result=fn(*args,**kwargs)future.set_result(result)exceptExceptionase:future.set_exception(e)# 线程退出前清理self._threads.discard(threading.current_thread())defshutdown(self,wait=True):self._shutdown=Truefor_inrange(len(self._threads)):self._work_queue.put(None)# 让所有工作线程退出ifwait:fortinself._threads:t.join()

4.4 完整示例:并发下载网页(I/O 密集型)

并发下载多个网页(IO 密集型)

importrequestsfromconcurrent.futuresimportThreadPoolExecutor,as_completed urls=["https://example.com","https://httpbin.org/get","https://www.python.org"]deffetch(url):resp=requests.get(url,timeout=5)returnurl,resp.status_codewithThreadPoolExecutor(max_workers=3)asexecutor:future_to_url={executor.submit(fetch,url):urlforurlinurls}forfutureinas_completed(future_to_url):url=future_to_url[future]try:url,status=future.result()print(f"{url}->{status}")exceptExceptionase:print(f"{url}失败:{e}")

五、python协程详解

5.1 协程基础概念

  1. 什么是协程
    协程是用户态的轻量级任务,完全由程序自身控制切换(无需操作系统参与)。多个协程可以在一个线程内并发执行,遇到 I/O 等待时主动让出 CPU,事件循环调度其他就绪协程继续运行。
  2. 为什么需要协程
    极高并发:一个线程可轻松创建数万甚至数十万个协程,内存开销极小(每个协程仅数百字节)。
    无锁编程:协程间切换不涉及共享资源竞争(单线程内串行执行),无需费力处理锁。

5.2 协程核心三要素

协程的运行依赖 3 个核心对象,这是理解协程的关键,三者的转换关系必须牢记:

核心对象定义核心作用能否直接被调度
事件循环(Event Loop)协程的调度中心管理所有任务,监听 IO 状态,自动切换可执行任务-
协程对象(Coroutine)async 函数调用后生成的对象封装协程逻辑,是任务的原始载体❌ 不能
Task 任务协程对象的封装体(继承自 Future)事件循环的最小调度单位,支持并发✅ 能

三者转换规则

  1. 协程函数 → 协程对象
    async def定义协程函数,直接调用函数不会执行,只会生成协程对象;

  2. 协程对象 → Task 对象

    • 显式转换(推荐):task = asyncio.create_task(coro),获得 Task 句柄,可控制、查询状态;
    • 隐式转换:await coro时事件循环内部自动包装为 Task,并注册到事件循环,但无法获得引用;
  3. Task 对象 → 事件循环调度执行
    事件循环运行 Task,Task 执行到await主动挂起,等待事件(I/O、定时器)。事件循环在此期间调度其他 Task,待事件发生后恢复该 Task 的执行。

5.3 协程实现与并发实战

5.3.1 async 和 await协程核心语法规则

Python 协程基于asyncio模块,核心依靠asyncawait两个关键字,同时内置隐式转换逻辑。

async 关键字作用
  1. 用于修饰普通函数,将其定义为协程函数;
  2. 协程函数直接调用不会执行内部业务逻辑,仅返回一个协程对象;
  3. 协程对象只是逻辑载体,本身无法被事件循环直接调度。
await 关键字使用约束与核心作用

使用约束:只能在 async 修饰的协程函数内部使用,普通同步函数中禁止出现;

核心作用

  • 暂停当前协程后续代码,主动挂起当前协程,让出执行控制权给事件循环,用于调度其他协程任务;
  • 等待后方异步 I/O 操作完成,I/O 就绪后恢复当前协程继续执行;
  • 是协程实现单线程多任务切换、异步并发的核心支撑。

后置对象隐式转换规则

  • await 后面可接收协程对象、Task 对象、Future 对象,底层自动处理转换:
  • 若后置是裸协程对象:asyncio 底层会自动将其封装为 Task 任务,注册到事件循环参与调度,无需手动写create_task()
    若已经手动通过create_task()封装为 Task:直接等待任务执行完毕,不会重复封装;
  • 场景选用:简单串行逻辑直接 await 协程对象 即可;需要并发、获取任务状态、设置回调时,必须手动创建 Task。

5.3.2 基础示例:await 自动封装协程对象

importasyncio# 定义协程函数asyncdefwork(name):print(f"任务{name}:开始执行")# await 后接协程对象,底层自动转为 Task 调度awaitasyncio.sleep(1)print(f"任务{name}:执行完毕")# 主协程入口asyncdefmain():# 调用协程函数,生成协程对象coro=work("测试任务")# await 自动把协程对象封装为 Task 并执行awaitcoro# 启动事件循环,运行主协程asyncio.run(main())

5.3.3 并发实战:手动创建Task + asyncio.gather

单纯顺序 await 多个协程只是串行执行,无法发挥协程并发优势;
想要真正并发,必须手动把协程对象封装为 Task,再通过asyncio.gather()批量调度。

importasyncioasyncdefwork(name,delay):print(f"任务{name}:开始执行,等待{delay}s")awaitasyncio.sleep(delay)print(f"任务{name}:执行完毕")returnf"{name}完成"asyncdefmain():# 手动将协程对象封装为 Task,加入事件循环待命task1=asyncio.create_task(work("A",2))task2=asyncio.create_task(work("B",1))# 并发等待所有 Task 执行完成results=awaitasyncio.gather(task1,task2)print("所有任务执行结果:",results)# 总耗时约 2s,实现真正并发asyncio.run(main())

5.4 协程底层调度原理、使用注意事项及异步本质

5.4.1 协程底层调度原理

  1. 调度模式:协作式调度(非抢占式)
    进程、线程是操作系统强制抢占式切换;协程没有操作系统参与,是任务遇到 await 主动让出控制权,属于用户态协作切换,除非协程主动让出控制权,否则当前协程一直占用。
  2. 完整切换流程
    • 协程执行到 await 触发 IO 等待 → 主动挂起,释放事件循环控制权;
    • 事件循环检索就绪队列,调度其他可运行的 Task 协程;
    • 原有 IO 操作完成后,事件循环重新唤醒原协程,继续执行后续代码。
  3. 性能优势:全程在用户态完成切换,无操作系统上下文切换开销,资源消耗极低。

5.4.2 协程为什么是异步的实现方式?体现在哪里

  1. 异步核心特征:非阻塞、等待不占用资源
    普通同步代码遇到 IO 会阻塞整个线程,原地空等占用资源;协程遇到 await 触发 IO 操作时(异步IO操作),仅瞬间完成请求发起、向事件循环注册监听事件,随后主动挂起并让出协程控制权,不会原地阻塞死等,事件循环可调度执行其他任务,实现 IO 等待时段的资源复用。
  2. 调度异步化
    由事件循环统一调度多个协程,任务执行顺序不由代码编写顺序决定,而是由 IO 就绪状态动态唤醒调度,完全契合异步编程调度思想。
  3. IO 等待可并行重叠
    所有异步网络请求、数据库读写等真实 IO 任务,底层逻辑和 asyncio.sleep 完全一致;多个协程无需串行挨个等待,IO 等待过程交由操作系统后台并行处理,等待时间相互重叠,这是协程异步高并发、省时间的根本原因。

六、进程 vs 线程vs 协程:核心对比

对比维度进程线程协程
调度方操作系统操作系统用户程序(自身)
资源开销极大中等极小
内存共享不共享共享完全共享
切换开销极低
锁竞争
多核利用✅ 支持❌ 受 GIL 限制❌ 单线程
并发能力极高(单机万级)
适用场景CPU 密集型IO 密集型高并发 IO 密集型
http://www.cnnetsun.cn/news/3438900.html

相关文章:

  • 如何在macOS菜单栏中打造你的私人系统监控中心?Stats应用深度解析
  • 如何通过3个步骤找到最适合你硬件的本地AI模型
  • 光电转换电路的设计与优化:从原理到实践
  • DevEco Code 的 Plan+Build 模式
  • FPGA锁相环(PLL)原理与PG2L50H开发板实战配置
  • # DalinX V8 灵鉴 V2:12维意识评测框架 —— 从 Tononi IIT 到 Friston FEP 的理论统一
  • C++编程从入门到实践:环境搭建、语法详解与项目实战
  • CANN/asc-devkit数据块最大值规约函数
  • CR Certification—美国CPSC 16 CFR 1700.20 防儿童开启包装CR认证
  • SPI硬件设计实战:从独立片选到菊花链拓扑的选型与应用
  • MacOS终端效率革命:Homebrew与Oh-My-Zsh的协同配置指南
  • AI-Infra 在证券金融行业的建设必要性、技术支撑与典型应用
  • 电路期末冲刺:从概念到应用的考点精讲与实战指南
  • goctl常用命令
  • Claude人机协同开发工作流:从需求到交付的四步闭环
  • 500+实战题库:LinkedIn IT运维技能深度解析与系统提升指南
  • 企业级数据可视化平台:Metabase架构设计与深度集成实战指南
  • 硬件工程师八大细分方向:从数字电路到射频设计的职业指南
  • 通义灵码不是代码生成器,而是开发者认知外延接口
  • Go03-基础语法与数据类型
  • Go05-函数与方法
  • 栈的C/C++实现:从数组到链表的三种经典结构
  • 如何应用 -中国多时期土地利用数据 CNLUCC|1980-2025|1km全国土地利用/土地覆盖栅格数据
  • 公考培训AI大模型横评:三家头部机构的技术底色差异有多大
  • 电解电容选型五大核心参数与工程实践
  • 小白程序员必看!收藏这份RAG技术指南,轻松玩转大模型知识增强检索
  • 突破分布式游戏服务器通信瓶颈:ET框架Actor模型的深度架构设计与性能优化实践
  • Phaser框架终极指南:3分钟快速掌握HTML5游戏开发
  • Ascend C关键分形格式详解
  • 图解软件开发:从需求到实现的四大核心建模图(用例图、类图、时序图、ER图)