鍍金池/ 教程/ Java/ 協(xié)程
數(shù)據(jù)庫訪問
循環(huán)
數(shù)組
錯(cuò)誤處理
面向?qū)ο?/span>
調(diào)試
游戲開發(fā)
文件 I/O
變量
迭代器
Web 編程
模塊
函數(shù)
元表
協(xié)程
垃圾回收機(jī)制
標(biāo)準(zhǔn)庫
決策
數(shù)據(jù)類型
運(yùn)行環(huán)境
操作符
字符串
基本語法
概述

協(xié)程

概述

協(xié)程具有協(xié)同的性質(zhì),它允許兩個(gè)或多個(gè)方法以某種可控的方式協(xié)同工作。在任何一個(gè)時(shí)刻,都只有一個(gè)協(xié)程在運(yùn)行,只有當(dāng)正在運(yùn)行的協(xié)程主動(dòng)掛起時(shí)它的執(zhí)行才會(huì)被掛起(暫停)。

上面的定義可能看上去比較模糊。接下來讓我講得很清楚一點(diǎn),假設(shè)我們有兩個(gè)方法,一個(gè)是主程序方法,另一個(gè)是一個(gè)協(xié)程。當(dāng)我們使用 resume 函數(shù)調(diào)用一個(gè)協(xié)程時(shí),協(xié)程才開始執(zhí)行。當(dāng)在協(xié)程調(diào)用 yield 函數(shù)時(shí),協(xié)程掛起執(zhí)行。再次調(diào)用 resume 函數(shù)時(shí),協(xié)程再從上次掛起的地方繼續(xù)執(zhí)行。這個(gè)過程一直持續(xù)到協(xié)程執(zhí)行結(jié)束為止。

協(xié)程中可用的函數(shù)

下面的表中列出 Lua 語言為支持協(xié)程而提供的所有函數(shù)以及它們的用法。

S.N. 方法和功能
1 coroutine.create(f):用函數(shù) f 創(chuàng)建一個(gè)協(xié)程,返回 thread 類型對(duì)象。
2 coroutine.resume(co[,val1,...]): 傳入?yún)?shù)(可選),重新執(zhí)行協(xié)程 co。此函數(shù)返回執(zhí)行狀態(tài),也可以返回其它值。
3 coroutine.running():返回正在運(yùn)行的協(xié)程,如果在主線程中調(diào)用此函數(shù)則返回 nil。
4 coroutine.status(co):返回指定協(xié)程的狀態(tài),狀態(tài)值允許為:正在運(yùn)行(running),正常(normal),掛起(suspended),結(jié)束(dead)。
5 coroutine.wrap(f):與前面 coroutine.create 一樣,coroutine.wrap 函數(shù)也創(chuàng)建一個(gè)協(xié)程,與前者返回協(xié)程本身不同,后者返回一個(gè)函數(shù)。當(dāng)調(diào)用該函數(shù)時(shí),重新執(zhí)行協(xié)程。
6 coroutine.yield(...):掛起正在執(zhí)行的協(xié)程。為此函數(shù)傳入的參數(shù)值作為執(zhí)行協(xié)程函數(shù) resume 的額外返回值(默認(rèn)會(huì)返回協(xié)程執(zhí)行狀態(tài))。

示例

讓我們通過下面的例子來理解一下協(xié)程這個(gè)概念。

co = coroutine.create(function (value1,value2)
   local tempvar3 =10
   print("coroutine section 1", value1, value2, tempvar3)
   local tempvar1 = coroutine.yield(value1+1,value2+1)
   tempvar3 = tempvar3 + value1
   print("coroutine section 2",tempvar1 ,tempvar2, tempvar3)
   local tempvar1, tempvar2= coroutine.yield(value1+value2, value1-value2)
   tempvar3 = tempvar3 + value1
   print("coroutine section 3",tempvar1,tempvar2, tempvar3)
   return value2, "end"
end)

print("main", coroutine.resume(co, 3, 2))
print("main", coroutine.resume(co, 12,14))
print("main", coroutine.resume(co, 5, 6))
print("main", coroutine.resume(co, 10, 20))

執(zhí)行上面的程序,我們可以得到如下的輸出結(jié)果:

coroutine section 1 3   2   10
main    true    4   3
coroutine section 2 12  nil 13
main    true    5   1
coroutine section 3 5   6   16
main    true    2   end
main    false   cannot resume dead coroutine

上面的例子到底做了些什么呢?

和前面說到的一樣,在例子中我們使用 resume 函數(shù)繼續(xù)執(zhí)行協(xié)程,用 yield 函數(shù)掛起協(xié)程。同樣,從例子中也可以看出如何為執(zhí)行協(xié)程的 resueme 函數(shù)返回多個(gè)值。下面我將逐步解釋上面的代碼。

  • 首先,我們創(chuàng)建了一個(gè)協(xié)程并將其賦給變量 co。此協(xié)程允許傳入兩個(gè)參數(shù)。
  • 第一次調(diào)用函數(shù) resume 時(shí),協(xié)程內(nèi)局部變量 value1 和 value2 的值分別為 3 和 2。
  • 為了便于理解,我們使用了局部變量 tempvar3 該變量被初始化為 10。由于變量 value1 的值為3,所以 tempvar3 在隨后的協(xié)程調(diào)用過程中被先后更新為 13 和 16。
  • 第一次調(diào)用 coroutine.yield 時(shí),為 resume 函數(shù)返回了值 4 和 3,這兩個(gè)值是由傳入的參數(shù) 3,2 分別加 1 后的結(jié)果,這一點(diǎn)可以從 yield 語句中得到證實(shí)。除了顯示指定的返回值外,resume 還收到隱式的返回值 true,該值表示協(xié)程執(zhí)行的狀態(tài),有 true 和 false 兩個(gè)可能取值。
  • 上面的例子中,我們還應(yīng)該關(guān)注在下一次調(diào)用 resume 時(shí)如何為協(xié)程傳入?yún)?shù)。從例子中可以看到,coroutine.yield 函數(shù)返回后為兩個(gè)變量賦值,該值即是第二次調(diào)用 resume 時(shí)傳入的參數(shù)。這種參數(shù)傳遞的機(jī)制讓可以結(jié)合前面?zhèn)魅氲膮?shù)完成很多新的操作。
  • 最后,協(xié)程中所有語句執(zhí)行完后,后面的調(diào)用就會(huì)返回 false 狀態(tài),同時(shí)返回 "cannot resume dead coroutine"消息。

另一個(gè)協(xié)程的示例

下面這例子中的協(xié)程使用 yield 函數(shù)和 resume 函數(shù)依次返回?cái)?shù)字 1 到 5。示例中,如果沒有協(xié)程對(duì)象或?qū)ο笠呀Y(jié)束(dead),則重新創(chuàng)建一個(gè)新的協(xié)程對(duì)象;若協(xié)程已經(jīng)存在,則執(zhí)行已經(jīng)存在的協(xié)程。

function getNumber()
   local function getNumberHelper()
      co = coroutine.create(function ()
      coroutine.yield(1)
      coroutine.yield(2)
      coroutine.yield(3)
      coroutine.yield(4)
      coroutine.yield(5)
      end)
      return co
   end
   if(numberHelper) then
      status, number = coroutine.resume(numberHelper);
      if coroutine.status(numberHelper) == "dead" then
         numberHelper = getNumberHelper()
         status, number = coroutine.resume(numberHelper);
      end
      return number
   else
      numberHelper = getNumberHelper()
      status, number = coroutine.resume(numberHelper);
      return number
   end
end
for index = 1, 10 do
   print(index, getNumber())
end

執(zhí)行上述的程序,我們可以得到如下的輸出結(jié)果:

1   1
2   2
3   3
4   4
5   5
6   1
7   2
8   3
9   4
10  5

大家經(jīng)常會(huì)把協(xié)程和多線程編程語言中的線程進(jìn)行對(duì)比,但我們要明白,協(xié)程有著與線程類似的特性,但是協(xié)程與線程的區(qū)別在于協(xié)程不能并發(fā),任意時(shí)刻只會(huì)有一個(gè)協(xié)程執(zhí)行,而線程允許并發(fā)的存在。(譯注:譯者認(rèn)為本質(zhì)上協(xié)程其是就是線程,不過是用戶態(tài)的線罷了,它將調(diào)度問題交由程序開發(fā)人員手動(dòng)完成。)

我們通過控制程序執(zhí)行順序以滿足獲取某些臨時(shí)信息的需求。配合全局變量的使用,協(xié)和會(huì)變得更加的靈活方便。

上一篇:函數(shù)下一篇:基本語法