import{_ as s,c as i,o as a,a4 as n}from"./chunks/framework.Cy9JvDAg.js";const c=JSON.parse('{"title":"2.6 - 协程（Coroutines）","description":"","frontmatter":{"title":"2.6 - 协程（Coroutines）","footer":true,"lastUpdated":true,"outline":false},"headers":[],"relativePath":"2.6.md","filePath":"2.6.md"}'),t={name:"2.6.md"},e=n(`<h2 id="_2-6-协程-coroutines" tabindex="-1">2.6 - 协程（Coroutines） <a class="header-anchor" href="#_2-6-协程-coroutines" aria-label="Permalink to &quot;2.6 - 协程（Coroutines）&quot;">​</a></h2><p>Lua支持<em>协程（Coroutines）</em>，其也被称为<em>协同式线程（collaborative multithreading）</em>。Lua中的协程表示一个独立执行线程。然而不同于多线程系统中的线程，协程只能通过显示调用让出函数来挂起自身的执行。</p><p>通过调用<a href="/lua5.4-manual-zh/6.2.html#coroutine.create">coroutine.create</a>你可以创建一个协程。此函数的唯一参数是用作协程主函数的方法。<em>create</em>函数只是创建一个新协程并返回其句柄（一个<em>thread</em>类型的对象），并不会启动协程。</p><p>你可以调用<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>来执行协程。当你首次调用<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>，需要将<a href="/lua5.4-manual-zh/6.2.html#coroutine.create">coroutine.create</a>返回的结果作为第一个参数传递，协程将会通过调用其主函数来启动执行。其余传递给<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>的参数会被传递到这个函数中。启动协程将会一直运行，直到它结束或<em>让出（yields）</em>。</p><p>协程可以通过两种方式来结束运行：通常情况下是其主函数返回（显式或隐式，在最后一条指令后）；特别情况是产生了未在保护下的错误。正常结束的情况下，<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>返回<strong>true</strong>，后跟协程的主函数返回的任意结果值。在发生错误时，<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>返回<strong>false</strong>，后边跟着错误对象。这种情况下，协程不会展开堆栈，所以在错误发生后可以通过调试API来调查。</p><p>协程通过调用<a href="/lua5.4-manual-zh/6.2.html#coroutine.yield">coroutine.yield</a>来让出。当协程让出时，相应的<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>会立刻返回，即使让出发生在内嵌的函数调用中（即不在主函数中，而是在主函数直接或间接调用的函数中）。当在让出的情况下，<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>也是返回<strong>true</strong>，后跟由<a href="/lua5.4-manual-zh/6.2.html#coroutine.yield">coroutine.yield</a>传递而来的值。当你下次重启同一个协程时，其将会在之前让出的地方继续执行，调用<a href="/lua5.4-manual-zh/6.2.html#coroutine.yield">coroutine.yield</a>的地方会返回由<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>传递过来的额外参数。</p><p>像<a href="/lua5.4-manual-zh/6.2.html#coroutine.create">coroutine.create</a>一样，<a href="/lua5.4-manual-zh/6.2.html#coroutine.wrap">coroutine.wrap</a>函数也可以创建协程，但不返回协程本身，而是返回一个用来启动协程的函数。任何传递到这个函数的参数都会作为<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>的额外参数传入。<a href="/lua5.4-manual-zh/6.2.html#coroutine.warp">coroutine.warp</a>返回所有<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>的值，除了第一个（那个布尔错误码）。与<a href="/lua5.4-manual-zh/6.2.html#coroutine.resume">coroutine.resume</a>不同，由<a href="/lua5.4-manual-zh/6.2.html#coroutine.wrap">coroutine.wrap</a>创建的函数不会传播任何错误给用户。这种情况下，此函数还会关闭协程（参见<a href="/lua5.4-manual-zh/6.2.html#coroutine.close">coroutine.close</a>）。</p><p>作为一个展示协程如何工作的例子，请考量以下代码：</p><div class="language-lua vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> foo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (a)</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">  print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;foo&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, a)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">  return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> coroutine.yield</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">2</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">*</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">a)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">end</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">co </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> coroutine.create</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">function</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (a,b)</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">      print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;co-body&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, a, b)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">      local</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> r </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> foo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(a</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">+</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">      print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;co-body&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, r)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">      local</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> r, s </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> coroutine.yield</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(a</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">b, a</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">b)</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">      print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;co-body&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, r, s)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">      return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> b, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;end&quot;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">end</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;main&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">coroutine.resume</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(co, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">10</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">))</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;main&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">coroutine.resume</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(co, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;r&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">))</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;main&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">coroutine.resume</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(co, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;x&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;y&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">))</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;main&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">coroutine.resume</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(co, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;x&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;y&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">))</span></span></code></pre></div><p>当你运行此代码，将产生以下输出：</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span>co-body 1       10</span></span>
<span class="line"><span>foo     2</span></span>
<span class="line"><span>main    true    4</span></span>
<span class="line"><span>co-body r</span></span>
<span class="line"><span>main    true    11      -9</span></span>
<span class="line"><span>co-body x       y</span></span>
<span class="line"><span>main    true    10      end</span></span>
<span class="line"><span>main    false   cannot resume dead coroutine</span></span></code></pre></div><br><p>你也可以通过C API来创建和处理协程：参见<a href="/lua5.4-manual-zh/4.6.html#lua_newthread">lua_newthread</a> ，<a href="/lua5.4-manual-zh/4.6.html#lua_resume">lua_resume</a>和<a href="/lua5.4-manual-zh/4.6.html#lua_yield">lua_yield</a>函数。</p>`,13),h=[e];function l(p,k,r,o,u,E){return a(),i("div",null,h)}const y=s(t,[["render",l]]);export{c as __pageData,y as default};
