V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Recommended Services
Amazon Web Services
LeanCloud
New Relic
ClearDB
monkeyNik
V2EX  ›  云计算

使用分时调度协程降低开发成本

  •  
  •   monkeyNik · 336 天前 · 1125 次点击
    这是一个创建于 336 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本文主要介绍在软件开发中,使用分时调度协程脚本语言是如何降低开发成本的。本文将以使用Melang脚本语言为例进行说明。这篇文章主要阐述概念和观点,至于语言,我也在此小推广一下,当然或许未来还会有各种各样的开发语言能够契合我们即将讨论到的这些概念和场景。

    所谓的成本,我认为分为两大部分:

    • 对开发者的开发成本
    • 对企业的开发成本

    但在针对这两部分进行讨论前,不得不提及协程这个概念。这是因为 Melang 中的协程与 Lua 或者 Go 的协程并不完全属于同一类别。我们暂时将协程分为两类:

    1. 传统协程
    2. 分时协程(也许叫它抢占式调度协程更为准确)

    传统的协程有两个特点:

    1. 通常是以函数的形式给出的
    2. 需要考虑协程的切换问题,也就是协程间的执行时序

    而分时协程,在 Melang 中的实现,它的特点是:

    1. 是以一个或一组代码文件,或者是一段代码片段的形式给出的
    2. 每一个协程是在一个相对独立的运行时环境中运行的,每个协程有自己的命名空间
    3. 程序不需要考虑切换问题,解释器将在每一个协程执行一段时间后自动切换

    在了解了上述内容后,我们回归到上面说到的成本的两个方面上。

    首先是对开发者而言的成本,这部分成本主要是程序逻辑复杂度。由于传统协程是一个协作的过程,哪一个先执行,哪一个后执行,哪一个应该在某种情况下执行都需要被深思熟虑后写出。因此,这也导致了程序作者需要耗费较大精力设计精密的程序结构,同时也导致了后续接手的开发人员上手的成本提升。

    如果换用了分时调度协程,则不需要过多精密安排协程执行顺序。在需要等待其他协程的处理结果时,可以直接调用对应的库函数进行数据的接收即可。其余情况下,以同步形式的代码逻辑书写即可,解释器会以异步的方式处理所有的协程。

    当然,精密设计的运行时序在某些场景下也非常适用,因此并不存在某一种协程模型完全普适所有场景的情况。

    接着是对企业的开发成本,这部分更多的是运行资源的成本。由于传统协程是一个函数,虽然函数本身可以是一个完整的功能,但在部分语言中并不支持函数的嵌套定义,这就会导致这个功能的封装性较差,从而使得代码阅读和复用变得更加困难。同时,函数的形式会给传统开发人员一种误导,认为函数应该是依赖一段主逻辑调用启动的。因此,常规的协程并发程序都是以一个主体逻辑拉起各个协程,然后一同运行。这些协程间都或多或少有一定关联关系。

    然而如果使用了分时调度协程,则不存在上述现象了。Melang 中的协程是一段独立的脚本代码,你可以随意封装你需要的类、函数,而不会受到语法限制。同时,最主要的,我们可以在同一个线程下,运行完全无关联的协程。也就是说,我们可以将多套程序运行在同一个线程下。所以,这里节省的成本就是:程序的可运行且可控的粒度将从进程或者线程级压缩到协程级别

    假设,我们经常会需要执行一些短时任务,并且好巧不巧,某些时间点会有大量短时任务,这些任务都会占用一个个的进程,这就导致了单机进程数量被大量占用。为此,也许我们会需要申请多台机器进行负载均衡。然而,事实上也许这些短时任务并不进行极大的运算,而是简单的网络 I/O 和统计累加,且这些结果并不要求严格的实时性。那么其实在绝大多数情况下,多台机器都处于半闲置状态,然而开发人员也并不太敢利用其中剩余的一部分资源,这就造成了资源的浪费。

    而如果换成协程粒度来执行的话,单一线程就可以跑数千协程,甚至或许只要 100 个进程就可以近似并行地跑 20 万个任务。

    当然,依旧不存在普适所有场景的解决方案,上面的例子也只是针对了一小部分场景进行了讨论。

    本文中仅阐述个人观点,由于个人的从业经历有限,或许有些场景并不正确,也希望大家能够多多指正,也期待你们给出宝贵的意见和建议,感谢阅读!

    lindt99cocoa
        1
    lindt99cocoa  
       335 天前
    你要找的是不是:线程
    monkeyNik
        2
    monkeyNik  
    OP
       335 天前
    @lindt99cocoa 应该说是 纤程 ,但这种比线程级别还要小的执行载体取决于各类语言的实现,在 lua 和 go 中就是协程,且是需要考虑到执行权问题的协程;在 Melang 里也可以称为协程,也可以说他就是一个纤程,它可以不用考虑调度问题,解释器会自动进行调度。
    hez2010
        3
    hez2010  
       335 天前 via Android
    都已经抢占式调度了那就已经不存在协程的"协"这个协作式概念了,直接叫它用户态线程就行了(事实上也就是用户态线程)。
    这种 N:M 线程模型是上个世纪就有的概念,只不过因为操作系统层面实现起来比较复杂所以只提供了 1:1 线程模型。
    monkeyNik
        4
    monkeyNik  
    OP
       335 天前
    @hez2010 是的,概念很早就有了。不管是协程、纤程还是用户态线程,同一个名称不同实现也就导致了概念不一致,但说到底只是个称呼。我想表达的也只是将可控的可执行单元缩小到更细粒度,可以降低一部分场景下的资源开销。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1565 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 17:18 · PVG 01:18 · LAX 09:18 · JFK 12:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.