V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
fgasdzxc
V2EX  ›  Go 编程语言

想探讨下 Go 中的网络编程模式

  •  
  •   fgasdzxc · 307 天前 · 3090 次点击
    这是一个创建于 307 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我知道 Go 是通过 goroutine 来实现高并发,在使用的时候,每个 IO 操作( Accpept 、Read 、Write )使用一个 goroutine 来处理,每个 goroutine 是同步阻塞的。

    我还知道 Go 的网络库底层是使用了 epoll 来监听文件描述符的,一旦文件描述符的数据就绪,就把对应的 goroutine 加入到可调度队列中。

    也就是说 Go 给我们提供的是同步阻塞的编程接口,使用起来非常方便简捷。但是其底层实现了 IO 多路复用,并且通过配合 GMP 的调度机制来使得就绪的文件描述符可以得到处理。在这个角度来看,Go 的网络编程模式是同步非阻塞的模式。尽管 goroutine 由于 IO 阻塞住了,但是底层的线程并没有阻塞(换了个线程接着调度之后的 goroutine ),并且通过底层的 IO 多路复用机制,一旦文件描述符就绪,相应的 goroutine 就可以被加入调度队列。

    上面这些是我对 Go 的网络编程模式的理解

    但是同时,又在很多博客中看到说 Go 是异步的网络编程模式,我对异步 IO 的理解是,主线程的调用直接返回,并且异步线程处理完会调用回调函数来通知主线程它处理完了返回结果。但是 Go 中显然是没有回调函数这个东西的,这算异步吗?

    认为 Go 是异步的网络编程模式的人认为,新开的 goroutine 不会阻塞当前 goroutine ,所以是异步的

    我想问一下我们通常所说的异步与异步 IO 是一个东西吗?
    16 条回复    2024-02-26 09:19:03 +08:00
    zzyphp111
        1
    zzyphp111  
       307 天前   ❤️ 1
    新开的 goroutine 不会阻塞当前 goroutine ,因此可以认为 Go 的网络编程模式是异步的。
    所以说异步与异步 I/O 在 Go 中是一个东西。而你说的异步 IO 在 go 中的表现形势又是通过 chan 等机制来实现所谓的回调,而这些都在用户态就完成了,所以可以理解是一种先进的异步 IO 模式
    mcfog
        2
    mcfog  
       307 天前 via Android   ❤️ 1
    这里有四个不同的概念
    non-block
    concurrency
    parallelism
    asynchronous
    nebkad
        3
    nebkad  
       307 天前   ❤️ 1
    如果你学 Rust ,那就可以很容易地明白他们为什么这么说,但你学 Go 我只能说你要多想。
    (对我是来挑事儿的 XD
    coyove
        4
    coyove  
       307 天前
    实际应用上讲是一个概念,因为你不会遇到 IO 以外需要异步的场景,也正是因为 iowait 的存在,才让 N 个核处理 C1M C10M 问题变得可能。

    话说比如高性能科学计算,你不可能通过在 10 核上开 100 goroutine 来变成 10x 性能。
    monkeyWie
        5
    monkeyWie  
       307 天前
    不要纠结什么阻塞、异步之类的术语,只需要明确 golang 底层是 epoll ,自动帮你把本应该异步处理的 io 通过协程做好了调度,在代码阻塞的时候实际上是不占用 cpu 资源的,这也是为什么 golang 做网络开发又简单性能又高的原因。
    Nazz
        6
    Nazz  
       307 天前
    阻塞/非阻塞指的是 IO 系统调用是否会阻塞当前线程, 同步/异步指的是任意某个操作是否会阻塞当前线程/协程
    thevita
        7
    thevita  
       307 天前
    我也觉得纠结这些意义不大,这里就说是 "golang 实现了用同步的语义(语言层面)使用 IO 多路复用( API/系统调用层面)"

    如果将来 golang 的 io 实现使用 io_uring 的话还可以说: "golang 实现了用同步的语义使用异步 IO “

    异步/同步 也可以统一嘛。
    GeekGao
        8
    GeekGao  
       307 天前
    关于“回调”: 虽然 Go 并没有显式的回调函数,但是通过 goroutines 和 channels ,我们可以实现类似的功能
    当一个 goroutine 完成其任务并将结果发送到 channel 时,这就像是在 “回调” 主线程。
    NessajCN
        9
    NessajCN  
       307 天前   ❤️ 6
    某些其他编程语言用户是真的招黑,跟编程届原神似的
    小心以后上哪儿都被人说学 xx 学的
    PTLin
        10
    PTLin  
       307 天前
    其实和操作系统一样的,发起读之后将这个线程挂到某个 waitlist 中,然后从运行队列里清除这个线程然后进行主动调度。当等待的条件满足后将 waitlist 中的线程放到运行队列里等待被重新调度到。
    kneo
        11
    kneo  
       307 天前 via Android
    需要标榜自己高性能的时候就说是异步,需要强调对程序员友好就说是同步。
    iseki
        12
    iseki  
       306 天前
    @Nazz 同步/异步的区分不是阻塞当前[线协]程与否,而是是否能立刻取回结果
    Nazz
        13
    Nazz  
       306 天前
    @iseki "立刻"这种表述也是有问题的
    iseki
        14
    iseki  
       306 天前 via Android
    @Nazz 确实,立刻还给了时间上的含有,也不合适…要不,“同步地返回”…得,循环了
    CLMan
        15
    CLMan  
       306 天前   ❤️ 4
    同步、异步、阻塞、非阻塞,本来就没有一个精确的定义,很容易因为理解不同而鸡同鸭讲,个人博客更是造成理解冲突的重灾区(个人博客充斥着二手知识,用词并非精确)。

    “异步”和“异步 IO”当然不是一回事,“异步”可以用来描述任何一段子程序的执行方式,而“异步 IO”,只能用来描述 IO 操作(读写文件和网络等)的执行方式。

    按照 Unix 的 IO 模型(《 Unix 网络编程卷 1 》,6.2 IO 模型),同步和异步用于描述内核和用户空间之间数据复制的过程,而阻塞和非阻塞用于描述等待资源就绪(网络资源、文件资源等)的过程。

    在某些书籍、博客中,或者非 IO 操作的上下文中,会相对抽象,将`阻塞`和`同步`都解释为等待,将`非阻塞`和`异步`都解释为立即返回,我无法评价这种解释是否正确,但至少在 Unix IO 模型中,这种解释是错误的。
    ------
    回归正题,“Go 中的网络编程模式”,你的困扰无非是该用其底层实现,还是其提供的 API 风格来描述,我个人是倾向于后者,但除非 Golang 团队亲口所说,纠结用什么定语来修饰“Go 的网络编程模式”没太多意义。
    lairdnote
        16
    lairdnote  
       305 天前
    @CLMan 这个理解比较全面。 现在 io_uring 的发展也不错 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   974 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 20:25 · PVG 04:25 · LAX 12:25 · JFK 15:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.