我们使用GPT-4来解释一下进程、线程和协程的区别。

进程 (Process)

区别:
  1. 独立性:进程是资源分配的基本单位,每个进程有自己独立的地址空间、内存、文件句柄等系统资源。
  2. 开销大:进程的创建和销毁需要较多的系统资源和时间,因为操作系统需要为每个进程分配独立的资源。
  3. 隔离性:进程之间相互独立,进程间通信(IPC)需要通过特定的机制,如管道、消息队列、共享内存等。
作用:
  • 适用于需要高度隔离和独立运行的任务。
  • 常用于多用户操作系统中,每个用户的程序运行在独立的进程中。

线程 (Thread)

区别:
  1. 共享资源:线程是CPU调度的基本单位,同一进程中的线程共享进程的地址空间和资源。
  2. 开销小:线程的创建和销毁比进程要轻量,因为线程共享进程的资源。
  3. 并发执行:线程可以并发执行,提高程序的响应速度和资源利用率。
作用:
  • 适用于需要频繁创建和销毁任务的场景。
  • 常用于需要并发处理的程序,如多线程服务器、图形界面程序等。

协程 (Coroutine)

区别:
  1. 轻量级:协程是一种用户态的轻量级线程,切换协程的开销非常小,不需要操作系统的参与。
  2. 非抢占式:协程是协作式调度,执行权由协程主动让出,控制更加灵活。
  3. 单线程执行:协程通常在一个线程内运行,避免了多线程的竞争和锁问题。
作用:
  • 适用于I/O密集型任务和需要大量并发的场景,如网络编程、爬虫等。
  • 通过协程可以实现高效的异步编程。

总结

  • 进程:适合独立运行的任务,隔离性强,但开销大。
  • 线程:适合并发执行的任务,资源共享,开销小,但需要处理同步问题。
  • 协程:适合大量并发的任务,轻量级,控制灵活,但通常在单线程内运行。

所以协程不能提升运算速度,只是适合需要IO等待的任务,最典型的就是网络通信。

协程最核心的机制就是event_loop,就像一个大脑,决定执行哪个任务。

coroutine和task的解释:

  • 1 coroutine
    • coroutine function:以async def开头的函数。
    • coroutine object:coroutine function调用时返回一个coroutine object。
  • 2 task:event_loop循环中可以执行的任务。

await:

  • 1 将coroutine变成task注册到event_loop
  • 2 将task的返回值进行返回

asyncio.run():

  • 1 建立一个event_loop,不停地找task进行执行

所有控制权的交回是显示的:

  • 1 await
  • 2 函数运行完毕

1 初探

import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(f"what is {what} delay is {delay}")


async def main():
    print(f"task start!!")
    await say_after(1, "hello")
    await say_after(1, "world")
    print(f"task end!!")

asyncio.run(main())

2 create_task

create_task可以将coroutine包装成一个task给event_loop去执行。

task1 = asyncio.create_task(say_after(1, "hello"))
task2 = asyncio.create_task(say_after(2, "world"))

3 enture_future

coroutine -> future -> task -> event_loop

asyncio.ensure_future(say_after(1, "hello"))

4 gather

gather的参数是若干个coroutine或者task,然后返回一个future值,然后await返回这个future时,相当于告诉event_loop等待全部的task,并且将全部task的结果放在list中返回。

直接处理coroutine

import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    return f"what is {what} delay is {delay}"


async def main():
    print(f"task start!!")
    ret = await asyncio.gather(say_after(1, "hello"), say_after(2, "world"))
    print(ret)
    print(f"task end!!")

asyncio.run(main())

直接处理future

import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    return f"what is {what} delay is {delay}"


async def main():
    print(f"task start!!")
    future1 = asyncio.ensure_future(say_after(1, "hello"))
    future2 = asyncio.ensure_future(say_after(1, "world"))
    futures = [future1, future2]
    ret = await asyncio.gather(*futures)
    print(f"ret is {ret}")
    print(f"task end!!")

asyncio.run(main())

直接处理task

import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    return f"what is {what} delay is {delay}"


async def main():
    print(f"task start!!")
    task1 = asyncio.create_task(say_after(1, "hello"))
    task2 = asyncio.create_task(say_after(2, "world"))
    ret = await asyncio.gather(task1, task2)
    print(ret)
    print(f"task end!!")

asyncio.run(main())

会话和信号量

详细见:https://blog.csdn.net/arkohut/article/details/139076652