golang,go,博客,开源,编程

概念:同步、异步、阻塞、非阻塞

Published on with 0 views and 0 comments

在计算机编程中,同步、异步、阻塞、非阻塞 是描述 I/O 操作行为的术语,尤其在多任务、并发编程和 I/O 操作中,它们定义了任务执行和任务间交互的方式。这些概念有时会让人困惑,但理解它们有助于优化程序的性能和响应能力。

让我们依次解释这四个概念。

1. 同步(Synchronous)与异步(Asynchronous)

这两个术语描述了操作完成的时机及其执行流程。

  • 同步(Synchronous):指操作必须按顺序执行。发起一个任务的代码会等待该任务完成后才能继续执行下一个任务。即,当前任务需要等到结果返回,才能继续执行下一个任务。
    举个例子:在同步模型下,如果你在函数中调用 A()B(),那么程序会等待 A() 完成后才会继续执行 B()
    // 同步
    resultA := A()  // 执行 A,等待它完成
    resultB := B()  // 然后执行 B
    
  • 异步(Asynchronous):指操作的执行不需要等待结果,操作会在后台进行,主程序可以继续执行其他任务。只有当操作完成时,程序才会收到通知,通常是通过回调函数、事件或状态检查等机制。
    举个例子:在异步模型下,A()B() 可能同时运行,而不需要等 A() 完成后才执行 B()。程序继续执行,不会被阻塞。
    // 异步
    go A()  // 在后台执行 A,继续执行主程序
    go B()  // 在后台执行 B,继续执行主程序
    

2. 阻塞(Blocking)与非阻塞(Non-blocking)

这两个术语描述了 I/O 操作或任务在执行过程中是否会阻塞程序的执行。

  • 阻塞(Blocking):在阻塞模型下,当一个 I/O 操作被发起时,调用该操作的线程会被阻塞,直到操作完成才能继续执行后续任务。也就是说,程序在执行某个操作时会等待该操作完成,不会继续执行其他任务。
    举个例子:在阻塞模式下,如果你执行一个网络请求,程序会等到请求返回结果后才能继续执行其他操作。
    // 阻塞
    data := networkRequest()  // 等待网络请求完成,阻塞
    fmt.Println(data)          // 网络请求完成后才会继续执行
    
  • 非阻塞(Non-blocking):在非阻塞模型下,当一个 I/O 操作被发起时,程序不会等待操作完成,而是立即返回并继续执行后续任务。通常,非阻塞操作会立即返回,告诉程序该操作还在进行中,程序可以通过某种方式(如轮询、事件等)来检查操作是否完成。
    举个例子:在非阻塞模式下,网络请求可能会立即返回,并告诉程序请求正在处理中。程序可以继续执行其他任务,直到请求完成。
    // 非阻塞
    success := nonBlockingNetworkRequest()  // 立即返回,不阻塞
    if success {
        fmt.Println("Request is still in progress")
    }
    

3. 同步与阻塞的关系

  • 同步阻塞:同步 I/O 操作通常是阻塞的,意味着调用该操作后,程序会等待操作完成并阻塞后续操作。最经典的例子是文件 I/O 操作:程序调用 Read() 时,直到文件完全读完后才会返回,程序在此期间是阻塞的。
  • 同步非阻塞:同步非阻塞的情况较少见。它表示操作是同步的,但不会阻塞调用线程。例如,某些文件系统或数据库操作可能提供非阻塞的同步调用。

4. 异步与阻塞的关系

  • 异步阻塞:异步与阻塞通常是相对独立的,但可以结合在一起。例如,某些异步操作(比如异步文件读写或网络请求)可能会通过回调机制返回结果,但在等待响应时会阻塞主线程或操作系统线程。尽管如此,操作的执行本身并不会阻塞调用线程。
  • 异步非阻塞:最常见的模式,操作在后台进行,不会阻塞主程序。调用线程发起操作后,继续执行其他任务。当操作完成时,会通过回调、事件或其他机制通知调用线程。比如,Node.js 使用事件驱动模型就是一种异步非阻塞的方式,Go 中的 Goroutines 也是异步非阻塞的。

5. 结合:如何理解同步、异步、阻塞、非阻塞的组合

操作类型同步/异步阻塞/非阻塞
同步阻塞同步阻塞
同步非阻塞同步非阻塞
异步阻塞异步阻塞
异步非阻塞异步非阻塞

1. 同步阻塞

  • 比如,传统的数据库查询,客户端发送查询请求后,需要等待数据库返回结果,直到操作完成,程序才会继续执行。
  • 例子:文件读写、传统的 HTTP 请求。

2. 同步非阻塞

  • 这种模式比较少见,但可以存在。例如某些同步 I/O 操作会立即返回状态,不会阻塞当前线程。
  • 例子:某些高效的数据库连接池,它们可以提供非阻塞的同步操作。

3. 异步阻塞

  • 这种组合不太常见,但有些应用可能会结合异步和阻塞。例如,后台执行某些任务,但在某些操作上依然会阻塞,直到操作完成。
  • 例子:某些任务队列系统,它可能会在内部异步执行任务,但阻塞任务的返回直到队列完成。

4. 异步非阻塞

  • 这是最常见的模式,特别适用于高并发的网络应用。操作发起后不阻塞主线程,可以继续执行其他任务,操作完成后通过回调通知。
  • 例子:Node.js、Go 的网络 I/O、异步文件操作。

6. 实际应用中的选择

在不同的应用场景中,你会选择适合的 I/O 模式来满足性能需求:

  • Web 服务器:常见的做法是使用异步非阻塞 I/O。因为 Web 服务器需要处理大量并发请求,使用同步阻塞会导致性能瓶颈。
  • 数据库操作:对于数据库查询,通常是同步阻塞的,因为查询操作需要等待数据库返回结果。
  • 实时通信:实时消息系统通常使用异步非阻塞 I/O,这样可以同时处理多个客户端请求,提高性能。
  • GUI 应用:通常使用异步 I/O 来避免界面阻塞,保证用户界面的流畅性。

总结

  • 同步 是指任务按顺序执行,后续任务必须等待当前任务完成后才能继续。
  • 异步 是指任务不需要等待当前任务完成,主线程可以继续执行其他任务。
  • 阻塞 是指当前任务执行时会阻塞调用线程,直到任务完成。
  • 非阻塞 是指当前任务执行时不会阻塞调用线程,任务可能立即返回并继续执行其他任务。

这四个概念结合在一起,可以帮助你在多线程、并发编程中选择适合的模型来处理不同的任务,提高程序性能和响应能力。


标题:概念:同步、异步、阻塞、非阻塞
作者:mooncakeee
地址:http://blog.dd95828.com/articles/2025/01/07/1736238918475.html
联系:scotttu@163.com