Lua中的協同程式 coroutine(轉)

来源:http://www.cnblogs.com/softidea/archive/2016/03/04/5242939.html
-Advertisement-
Play Games

Lua中的協程和多線程很相似,每一個協程有自己的堆棧,自己的局部變數,可以通過yield-resume實現在協程間的切換。不同之處是:Lua協程是非搶占式的多線程,必須手動在不同的協程間切換,且同一時刻只能有一個協程在運行。並且Lua中的協程無法在外部將其停止,而且有可能導致程式阻塞。 協同程式(C


  Lua中的協程和多線程很相似,每一個協程有自己的堆棧,自己的局部變數,可以通過yield-resume實現在協程間的切換。不同之處是:Lua協程是非搶占式的多線程,必須手動在不同的協程間切換,且同一時刻只能有一個協程在運行。並且Lua中的協程無法在外部將其停止,而且有可能導致程式阻塞。

 

協同程式(Coroutine):

  三個狀態:suspended(掛起,協同剛創建完成時或者yield之後)、running(運行)、dead(函數走完後的狀態,這時候不能再重新resume)。

  coroutine.create(arg):根據一個函數創建一個協同程式,參數為一個函數

  coroutine.resume(co):使協同從掛起變為運行(1)激活coroutine,也就是讓協程函數開始運行;(2)喚醒yield,使掛起的協同接著上次的地方繼續運行。該函數可以傳入參數

  coroutine.status(co):查看協同狀態

  coroutine.yield():使正在運行的協同掛起,可以傳入參數

  resume函數的兩種用途雖然都是使協同掛起,但還是有些許差異的,看下麵這個例子:

複製代碼
coroutineFunc = function (a, b) 
    for i = 1, 10 do
        print(i, a, b)
        coroutine.yield()
    end
end

co2 = coroutine.create(coroutineFunc)        --創建協同程式co2
coroutine.resume(co2, 100, 200)                -- 1 100 200 開啟協同,傳入參數用於初始化
coroutine.resume(co2)                        -- 2 100 200 
coroutine.resume(co2, 500, 600)                -- 3 100 200 繼續協同,傳入參數無效

co3 = coroutine.create(coroutineFunc)        --創建協同程式co3
coroutine.resume(co3, 300, 400)                -- 1 300 400 開啟協同,傳入參數用於初始化
coroutine.resume(co3)                        -- 2 300 400 
coroutine.resume(co3)                        -- 3 300 400 
複製代碼

   Lua中協同的強大能力,還在於通過resume-yield來交換數據:

  (1)resume把參數傳給程式(相當於函數的參數調用);

  (2)數據由yield傳遞給resume;

  (3)resume的參數傳遞給yield;

  (4)協同代碼結束時的返回值,也會傳給resume

   協同中的參數傳遞形勢很靈活,一定要註意區分,在啟動coroutine的時候,resume的參數是傳給主程式的;在喚醒yield的時候,參數是傳遞給yield的。看下麵這個例子:

co = coroutine.create(function (a, b) print("co", a, b, coroutine.yield()) end)
coroutine.resume(co, 1, 2)        --沒輸出結果,註意兩個數字參數是傳遞給函數的
coroutine.resume(co, 3, 4, 5)        --co 1 2 3 4 5,這裡的兩個數字參數由resume傳遞給yield 

  Lua的協同稱為不對稱協同(asymmetric coroutines),指“掛起一個正在執行的協同函數”與“使一個被掛起的協同再次執行的函數”是不同的,有些語言提供對稱協同(symmetric coroutines),即使用同一個函數負責“執行與掛起間的狀態切換”。

   註意:resume運行在保護模式下,因此,如果協同程式內部存在錯誤,Lua並不會拋出錯誤,而是將錯誤返回給resume函數。

   以下是我個人的一點理解:

  (1)resume可以理解為函數調用,並且可以傳入參數,激活協同時,參數是傳給程式的,喚醒yield時,參數是傳遞給yield的;

  (2)yield就相當於是一個特殊的return語句,只是它只是暫時性的返回(掛起),並且yield可以像return一樣帶有返回參數,這些參數是傳遞給resume的。

為了理解上面兩句話的含義,我們來看一下如何利用Coroutine來解決生產者——消費者問題的簡單實現:

複製代碼
produceFunc = function()
    while true do
        local value = io.read()
        print("produce: ", value)
        coroutine.yield(value)        --返回生產的值
    end
end

consumer = function(p)
    while true do
        local status, value = coroutine.resume(p);        --喚醒生產者進行生產
        print("consume: ", value)
    end
end

--消費者驅動的設計,也就是消費者需要產品時找生產者請求,生產者完成生產後提供給消費者
producer = coroutine.create(produceFunc)
consumer(producer)
複製代碼

這是一種消費者驅動的設計,我們可以看到resume操作的結果是等待一個yield的返回,這很像普通的函數調用,有木有。我們還可以在生產消費環節之間加入一個中間處理的環節(過濾器):

複製代碼
produceFunc = function()
    while true do
        local value = io.read()
        print("produce: ", value)
        coroutine.yield(value)        --返回生產的值
    end
end

filteFunc = function(p)
    while true do
        local status, value = coroutine.resume(p);
        value = value *100            --放大一百倍
        coroutine.yield(value)
    end
end

consumer = function(f, p)
    while true do
        local status, value = coroutine.resume(f, p);        --喚醒生產者進行生產
        print("consume: ", value)
    end
end

--消費者驅動的設計,也就是消費者需要產品時找生產者請求,生產者完成生產後提供給消費者
producer = coroutine.create(produceFunc)
filter = coroutine.create(filteFunc)
consumer(filter, producer)
複製代碼

  可以看到,我們在中間過濾器中將生產出的值放大了一百倍。

  通過這個例子應該很容易理解coroutine中如何利用resume-yield調用來進行值傳遞了,他們像“調用函數——返回值”一樣的工作,也就是說resume像函數調用一樣使用,yield像return語句一樣使用。coroutine的靈活性也體現在這種通過resume-yield的值傳遞上。

http://www.cnblogs.com/sifenkesi/p/3824321.html

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.設計模式的概念: 設計模式:設計模式(Design pattern)是一套被反覆使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。 2.設計模式的優點: 為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 ---------簡單工廠設計模式 所謂簡單工廠設計模式,就肯定有一個工廠類,
  • 在WPF中顯示一張圖片,本是一件再簡單不過的事情。一張圖片,一行XAML代碼即可。 但是前段時間遇到了一件奇怪的事: 開發機上運行正常的程式,在某些客戶機器上卻顯示不了圖片,而且除了這個問題,其它運行情況都正常。開始排查問題吧,先檢查代碼,然後檢查編譯打包過程,並沒有發現任何問題。再然後去客戶機器上
  • using Microsoft.AspNet.Identity; public ActionResult AddRole(String name){ using (var roleManager = new RoleManager<IdentityRole>(new RoleStore<Identi
  • 在C#中,如果要實現兩個列表的左鏈接查詢,我們的一般用法就是用的linq表達式就是 List<Pet> pets = new List<Pet>{ new Pet { Name="Barley", Age=8 }, new Pet { Name="Boots", Age=4 }, new Pet {
  • 本人也尚在學習使用之中,錯誤之處請大家指正。 開發環境:vs2015 UP1 項目環境:asp.net 4.6.1 模板為:asp.net 5 模板 identity版本為:asp.net identity 3.0.0 如圖: 建成後的項目已經和之前的模板建成的項目有非常大的不同了。identity
  • 每次寫分頁導航的時候都要在html頁面寫一堆標簽和樣式,太麻煩了,所以乾脆自己動手封裝一個自己喜歡的類直接生成。 一、PageHelper類: /// <summary> /// 分頁導航 /// </summary> /// <param name="pageNum">當前第幾頁</param>
  • 好久沒有寫博客了,這段時間準備寫一下字元串函數 QQ群: 499092562;歡迎交流 字元串函數: 1、LEN(需要獲取長度的字元串) 返回:字元串的長度 示例: SELECT LEN('小搬運工很帥!') 2、RIGHT(需要被從右邊截取的字元串,截取的開始下標,截取的長度) 返回:右邊的字元串
  • http://www.ourd3js.com/wordpress/
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...