Kotlin 的协程是真协程吗?被 b 站博主搞蒙了 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
714105382
V2EX    Kotlin

Kotlin 的协程是真协程吗?被 b 站博主搞蒙了

  •  
  •   714105382 2022-01-25 15:51:28 +08:00 via iPhone 8487 次点击
    这是一个创建于 1421 天前的主题,其中的信息可能已经有所发展或是发生改变。

    能做到类似 golang goroutine 完全不阻塞任何 os thread 进行 io 之类的访问并在得到结果后自动把协程挂载到线程继续执行?

    视频上说不能: [ [码上开学] 到底什么是「非阻塞式」挂起?协程真的比线程更轻量级吗?-哔哩哔哩] https://b23.t/qIkWUmo

    27 条回复    2022-12-16 12:44:55 +08:00
    zxjunz
        1
    zxjunz  
       2022-01-25 16:05:11 +08:00
    协程简单理解就是用同步式的写法去写异步的代码,防止回调地狱。反编译 kotlin 到 java ,本质上还是一层回调嵌套一层回。因此,并不会比线程轻量级。至于你说的,能否实现 golang 的协程效果,完全是可以的,甚至就是为此而设计的。
    jameslan
        2
    jameslan  
       2022-01-25 16:07:49 +08:00
    coroutines 都差不多,算上 js 的,python 的,等等等等。似乎 C#的最早?但是不叫 coroutines

    其实就是借助编译器,把函数拆成一个一个的 task ,然后用 event/message loop 来处理
    Goooler
        3
    Goooler  
       2022-01-25 16:10:46 +08:00
    Kotlin 协程在 Jvm 上的实现就是线程,其他平台上的实现不清楚。
    wellsc
        4
    wellsc  
       2022-01-25 16:11:08 +08:00
    stackfull coroutines
    Kasumi20
        5
    Kasumi20  
       2022-01-25 16:13:06 +08:00
    @zxjunz Java 能写回调吗?把局部变量的访问全部推到堆上?
    sagaxu
        6
    sagaxu  
       2022-01-25 16:14:33 +08:00 via Android
    不能,kt 协程里不能调用阻塞线程的方法,包括且不仅限于文件 IO ,网络 IO
    zxjunz
        7
    zxjunz  
       2022-01-25 16:17:38 +08:00
    @Kasumi20 #5 匿名内部类罢了,所有局部变量都会通过构造函数传到这个内部类里
    Leviathann
        8
    Leviathann  
       2022-01-25 16:20:02 +08:00
    看最终调用的 io 把
    如果在协程里调用阻塞 io 那协程所在的线程还是会被阻塞
    如果因为计算任务停住还能靠线程池的任务偷取

    go 应该是全链路非阻塞 + 内置调度器,所以可以随便调
    looplj
        9
    looplj  
       2022-01-25 16:42:01 +08:00
    go 的协程也会阻塞系统线程啊

    只是 Go 的所有 IO 操作被封装过而已,不会直接调用系统 io

    和 Kotlin 的效果是一样的,只是 kotlin 的想要不阻塞系统 thread ,需要调用特定 API 而已
    fpure
        10
    fpure  
       2022-01-25 16:52:22 +08:00
    协程就是用户态可重入的函数或过程,有的是手动重入比如生成器,有的是自动重入比如 async/await/绿色线程
    fpure
        11
    fpure  
       2022-01-25 16:56:15 +08:00
    协程的关键就是用户态的可重入,其他有栈无栈、自动重入手动重入都是基于此的概念
    tabris17
        12
    tabris17  
       2022-01-25 17:47:35 +08:00
    你应该先区分协程和异步IO的关系
    wxjggr
        13
    wxjggr  
       2022-01-25 18:43:08 +08:00 via Android
    @zxjunz kotlin 协程底层并不是回调嵌套,而是基于状态机的递归调用。
    xfriday
        14
    xfriday  
       2022-01-25 20:45:30 +08:00
    go 里面的 io 都是被包装过的,阻塞会自动调度走,kotlin 你用那些包装过的 io 也可以,不然会阻塞跑这个 coroutine 的线程,( cgo 调用系统阻塞 io ,调度器就没辙了)
    unco020511
        15
    unco020511  
       2022-01-25 22:02:56 +08:00
    kotlin for jvm 的协程是包装的线程,非操作系统层级的协程
    2i2Re2PLMaDnghL
        16
    2i2Re2PLMaDnghL  
       2022-01-26 10:08:16 +08:00
    与协程( coroutine )相对的概念不是线程( thread )、进程( process ),而是子例程( subroutine )
    最夸张地说,使用 Kafka Celery 之类的工具作为唯一信道可以构造跨进程甚至跨机器的协程。
    至于非阻塞 io ,只是和协程写法非常搭配罢了。但你也可以用 ponylang 那样的纯消息模式。

    @zxjunz kotlin 语言层面定义了一次性续延( one time continuation ),在那基础上构建的协程,我不认为编译到回调链能够正确地实现之,尤其是涉及控制结构(条件 / 循环)的时候。

    @Kasumi20 我记得是很早就能写了(看到写 stream 的都写回调)。不过蕴含一个障碍,不能直接修改外层词法作用域的变量,必须使用容器类型,我认为这符合 #7 所说。
    lasuar
        17
    lasuar  
       2022-01-26 10:23:13 +08:00 via iPhone
    如果是系统调用应该还是会占用线程的
    fpure
        18
    fpure  
       2022-01-26 11:22:13 +08:00
    @unco020511 难道还有操作系统层级的协程?协程本来就是应用自己实现的
    SoloCompany
        19
    SoloCompany  
       2022-01-26 19:57:33 +08:00   1
    操作系统哪来的协成概念, 所有协程的概念都是语言提供的, go 是 runtime 层面直接提供, kotlin 则是一个统一的抽象, 在不同的 runtime 上提供不同的实现, 基本上都是翻译成状态机的实现
    shyling
        20
    shyling  
       2022-01-26 21:58:02 +08:00
    协程是协程,异步 IO 是异步 IO 。。
    unco020511
        21
    unco020511  
       2022-01-27 09:41:24 +08:00
    @fpure # 18 是吗,那可能是我理解错了吧
    kingbill
        22
    kingbill  
       2022-03-11 16:21:18 +08:00
    据我的了解,计算机领域协程没有统一的定义(要说统一可能就是线程再上层的抽象),不同语言中对协程的定义都不太一样,不像线程是依赖操作系统的。真协程……不太理解你说的
    D3EP
        23
    D3EP  
       2022-04-14 16:12:36 +08:00
    协程肯定是跑在线程上的,操作系统就没有协程的概念。
    「非对称协程」大多数都是类似 Kotlin 这种实现,将一个函数体拆成多个 subroutine ,执行异步操作时,通过 continuation 保存上下文状态(包括代码行号、局部变量),并从当前函数退出;当异步操作完成时,会通过 continuation 重新进入该函数,并恢复上下文。
    D3EP
        24
    D3EP  
       2022-05-04 20:00:16 +08:00
    上面说错了,应该是「无栈协程」大多数都是类似 Kotlin 这种实现,将一个函数体拆成多个 subroutine ,执行异步操作时,通过 continuation 保存上下文状态(包括代码行号、局部变量),并从当前函数退出;当异步操作完成时,会通过 continuation 重新进入该函数,并恢复上下文。

    Golang 那种是有栈协程。
    Pantheoon
        25
    Pantheoon  
       2022-09-16 20:39:52 +08:00
    其实就是回调,没那么难理解,举个例子:
    doSth(xxx,new Listener(){
    success(){}
    })
    success 就是写在回调里面的,这种方式一个是比较丑陋,第二个是会有回调地狱的问题,doSth 可以跑在主线程,success 可以跑在子线程里面,后面为了解决丑陋的问题,就有了 await 这个关键字,js 和 c#都有,语法就变成了这样:
    await doSth()
    success()
    看到没有,如果有 await 他的语法是等价于上面那种东西的,doSth 可以跑在主线程,success 跑在了子线程里面,也就是用同步的方式写异步代码,线程发生了切换,但执行的顺序是同步的,本质上是回调
    然后到了 kotlin,首先,kotlin 吹嘘协程是对开发产生了误导,他的本质其实就是类似 await,通过语法把回调屏蔽掉:
    launch{
    doSth()
    success()
    }
    suspend doSth()
    而 suspend 关键字就是类似于 await,async 的 async 一样,其实就是打个标记,告诉编译器,后面可以加回调,当线程执行 success 时,doSth 方法没有被执行,也就是所谓的挂起来了,而添加回调的方式叫做 continuation,也就是反编译后是类似这样的语法
    doSth().continuation(success())
    大概这样子
    Pantheoon
        26
    Pantheoon  
       2022-09-16 20:43:15 +08:00
    如果是通过回调的方式,除了 success 方法,还有一个 error 方法
    doSth(xxx,new Listener(){
    success(){}
    error(){}
    })
    但是 kotlin 里面回调的语法是没有处理 error 的,所以它又搞了一堆异常机制,异常在协程里咋传播的,然后咋处理,设计的还挺复杂
    ExplodingDragon
        27
    ExplodingDragon  
       2022-12-16 12:44:55 +08:00
    “轻量”只是相对的概念,对于 CPU 密集的任务改用协程实现并不会有显著的性能提升,协程的主要目的是尽量避免无意义的等待 .
    关于     帮助文档     自助推广系统     博客     API     FAQ   &nsp; Solana     902 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 21:06 PVG 05:06 LAX 13:06 JFK 16:06
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86