zoukankan      html  css  js  c++  java
  • Routine Subroutine Coroutine 子程序 协程 子例程

    https://en.wikipedia.org/wiki/Subroutine

    In computer programming, a subroutine is a sequence of program instructions that perform a specific task, packaged as a unit. This unit can then be used in programs wherever that particular task should be performed.

    Subprograms may be defined within programs, or separately in libraries that can be used by multiple programs. In different programming languages, a subroutine may be called a procedure, a function, a routine, a method, or a subprogram. The generic term callable unit is sometimes used.[1]

    Subroutines are special cases of ... coroutines.

    https://en.wikipedia.org/wiki/Coroutine

    Coroutines are computer-program components that generalize subroutines for non-preemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations. Coroutines are well-suited for implementing familiar program components such as cooperative tasksexceptionsevent loopsiteratorsinfinite lists and pipes.

    According to Donald KnuthMelvin Conway coined the term coroutine in 1958 when he applied it to construction of an assembly program.[1] The first published explanation of the coroutine appeared later, in 1963.[2]

    Comparison with subroutines[edit]

    Subroutines are special cases of coroutines.[3] When subroutines are invoked, execution begins at the start, and once a subroutine exits, it is finished; an instance of a subroutine only returns once, and does not hold state between invocations. By contrast, coroutines can exit by calling other coroutines, which may later return to the point where they were invoked in the original coroutine; from the coroutine's point of view, it is not exiting but calling another coroutine.[3] Thus, a coroutine instance holds state, and varies between invocations; there can be multiple instances of a given coroutine at once. The difference between calling another coroutine by means of "yielding" to it and simply calling another routine (which then, also, would return to the original point), is that the relationship between two coroutines which yield to each other is not that of caller-callee, but instead symmetric.

    Any subroutine can be translated to a coroutine which does not call yield.[4]

    Here is a simple example of how coroutines can be useful. Suppose you have a consumer-producer relationship where one routine creates items and adds them to a queue and another removes items from the queue and uses them. For reasons of efficiency, you want to add and remove several items at once. The code might look like this:

    var q := new queue
    
    coroutine produce
        loop
            while q is not full
                create some new items
                add the items to q
            yield to consume
    
    coroutine consume
        loop
            while q is not empty
                remove some items from q
                use the items
            yield to produce
    

    The queue is then completely filled or emptied before yielding control to the other coroutine using the yield command. The further coroutines calls are starting right after the yield, in the outer coroutine loop.

    Although this example is often used as an introduction to multithreading, two threads are not needed for this: the yield statement can be implemented by a jump directly from one routine into the other.

    Comparison with threads[edit]

    Coroutines are very similar to threads. However, coroutines are cooperatively multitasked, whereas threads are typically preemptively multitasked. This means that coroutines provide concurrency but not parallelism. The advantages of coroutines over threads are that they may be used in a hard-realtime context (switching between coroutines need not involve any system calls or any blocking calls whatsoever), there is no need for synchronisation primitives such as mutexes, semaphores, etc. in order to guard critical sections, and there is no need for support from the operating system.

    It is possible to implement coroutines using preemptively-scheduled threads, in a way that will be transparent to the calling code, but some of the advantages (particularly the suitability for hard-realtime operation and relative cheapness of switching between them) will be lost.

    Comparison with generators[edit]

    Generators, also known as semicoroutines,[5] are a subset of coroutines. Specifically, while both can yield multiple times, suspending their execution and allowing re-entry at multiple entry points, they differ in coroutines' ability to control where execution continues immediately after they yield, while generators cannot, instead transferring control back to the generator's caller.[6] That is, since generators are primarily used to simplify the writing of iterators, the yield statement in a generator does not specify a coroutine to jump to, but rather passes a value back to a parent routine.

    However, it is still possible to implement coroutines on top of a generator facility, with the aid of a top-level dispatcher routine (a trampoline, essentially) that passes control explicitly to child generators identified by tokens passed back from the generators:

    var q := new queue
    
    generator produce
        loop
            while q is not full
                create some new items
                add the items to q
            yield consume
    
    generator consume
        loop
            while q is not empty
                remove some items from q
                use the items
            yield produce
    
    subroutine dispatcher
        var d := new dictionary(generatoriterator)
        d[produce] := start produce
        d[consume] := start consume
        var current := produce
        loop
            current := next d[current]
    

    A number of implementations of coroutines for languages with generator support but no native coroutines (e.g. Python[7] before 2.5) use this or a similar model.

    Comparison with mutual recursion[edit]

    Using coroutines for state machines or concurrency is similar to using mutual recursion with tail calls, as in both cases the control changes to a different one of a set of routines. However, coroutines are more flexible and generally more efficient. Since coroutines yield rather than return, and then resume execution rather than restarting from the beginning, they are able to hold state, both variables (as in a closure) and execution point, and yields are not limited to being in tail position; mutually recursive subroutines must either use shared variables or pass state as parameters. Further, each mutually recursive call of a subroutine requires a new stack frame (unless tail call elimination is implemented), while passing control between coroutines uses the existing contexts and can be implemented simply by a jump.

    Common uses

    Coroutines are useful to implement the following:

    • State machines within a single subroutine, where the state is determined by the current entry/exit point of the procedure; this can result in more readable code compared to use of goto, and may also be implemented via mutual recursion with tail calls.
    • Actor model of concurrency, for instance in video games. Each actor has its own procedures (this again logically separates the code), but they voluntarily give up control to central scheduler, which executes them sequentially (this is a form of cooperative multitasking).
    • Generators, and these are useful for streams – particularly input/output – and for generic traversal of data structures.
    • Communicating sequential processes where each sub-process is a coroutine. Channel inputs/outputs and blocking operations yield coroutines and a scheduler unblocks them on completion events. Alternatively, each sub-process may be the parent of the one following it in the data pipeline (or preceding it, in which case the pattern can be expressed as nested generators).
    • Reverse communication, commonly used in mathematical software, wherein a procedure such as a solver, integral evaluator, ... needs the using process to make a computation, such as evaluating an equation or integrand.
  • 相关阅读:
    033 流程控制之if判断
    032 基本运算符
    031 格式化输出的三种方式
    030 Python与用户交互
    029 解压缩
    028 布尔类型
    027 字典类型
    026 列表类型
    025 字符串类型
    023 数据类型基础
  • 原文地址:https://www.cnblogs.com/rsapaper/p/7772302.html
Copyright © 2011-2022 走看看