歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> nginx和lua的協程

nginx和lua的協程

日期:2017/2/27 15:48:53   编辑:Linux教程
1、緣起
我最早接觸協程時,對這東西很費解,甚至我看了lua的協程源碼實現後,這個疑慮還是沒有消除。直到有次在需要用異步編程時,對協程的理解一下子明白了。所以希望用從異步的角度解釋協程,能讓您有跟我一樣的收獲。

2、寫過的
我們的業務經常需要第三方服務打交道,比如db, nosql, http api等。這種交互要麼是阻塞的,要麼是異步的。
在nodejs裡的異步處理方式:
db.query('users', {name: name}, function(err, users) {
deal_with(users);
});
nodejs裡處理異步很簡單,注冊個回調即可。編程世界是多元的,每種文化都非常優秀,往往思維的碰撞會產生一些有意思的方式。我們習慣用順序的方式寫代碼,如果不關心這是阻塞或是異步就很理想了,只要語言保證性能足夠好。
users = db.query('users', {name: name});
deal_with(users);
可能你會認為代碼會阻塞在db.query,等有結果後才會去調用deal_with。那如果加入協程的概念後呢?一切變的很有意思。

3、什麼是協程?
協程是一種特殊的函數,可以在執行的過程中隨時暫時,隨時繼續執行。這是我的理解。
function foo()
    a();
    b();
    c();
end

我們知道當我們調用foo()時,直到函數有返回或終止時才會結束執行。但是如果foo是個協程(我說過協程是一個特殊的函數)。它可以在執行到a() 時,不繼續執行,先返回。等你需要時繼續調用,但下次是從上次暫停的位置繼續執行,也就是從b開始。這裡很重要的一點是協程的暫時不是阻塞,我們會繼續講 解。所以當我們把協程引入前面的db.query例子時,如果一切如我們所希望的,它就是同步的寫法,異步的實現,誰悄悄做了手腳呢?服務器和協程。

4、nginx和lua的絕配
服務器有個設計原則:永遠不能阻塞。nginx作為非常優秀的服務器,這點發揮的非常極致。在nginx裡有很多的體現異步的地方。我們繼續以上面的例子為例:
function foo() // foo本身是個協程,由nginx調用
users = db.query('users', {name: name}); // 此處由nginx發起db的連接請求,因為異步這裡先暫停協程
deal_with(users); // 當請求有響應得到處理時,繼續執行協程,這些才運行
end

通過nginx的異步機制和lua的協程,很容易實現這種同步寫法,異步實現的模型,但對開發人員而言,不用關心內部做了什麼。

5、lua裡如何實現協程
lua本身設計是c的膠體,除了可以寫lua腳本語言代碼,還可以用c調用lua的c接口。在協程這個地方也是如此。
既然上面提到nginx(c實現的),這裡將列兩種使用協程的方式:
a、腳本語言裡使用
co = coroutine.create(function ()
for i=1,10 do
print("co", i)
coroutine.yield()
end
end)

coroutine.resume(co) // 輸出 co 1
coroutine.resume(co) // 輸出 co 2
coroutine.resume(co) // 輸出 co 3

co是個協程,是個特殊的函數
coroutine.yield是暫停(掛起)協程
coroutine.resume是繼續執行(喚醒)協程

b、c調用方式
參考國內研究lua的前輩的文章: Lua 5.2 如何實現 C 調用中的 Continuation
Copyright © Linux教程網 All Rights Reserved