Lua之協同程序(coroutine)

什麼是協同(coroutine)?

Lua 協同程序(coroutine)與線程比較類似:擁有獨立的堆棧,獨立的局部變量,獨立的指令指針,同時又與其它協同程序共享全局變量和其它大部分東西。

協同是非常強大的功能,但是用起來也很複雜。

線程和協同程序區別

線程與協同程序的主要區別在於,一個具有多個線程的程序可以同時運行幾個線程,而協同程序卻需要彼此協作的運行。

在任一指定時刻只有一個協同程序在運行,並且這個正在運行的協同程序只有在明確的被要求掛起的時候纔會被掛起。

協同程序有點類似同步的多線程,在等待同一個線程鎖的幾個線程有點類似協同。

基本語法

方法描述
coroutine.create()創建coroutine,返回coroutine, 參數是一個函數,當和resume配合使用的時候就喚醒函數調用
coroutine.resume()重啓coroutine,和create配合使用
coroutine.yield()掛起coroutine,將coroutine設置爲掛起狀態,這個和resume配合使用能有很多有用的效果
coroutine.status()查看coroutine的狀態
注:coroutine的狀態有三種:dead,suspend,running,具體什麼時候有這樣的狀態請參考下面的程序
coroutine.wrap()創建coroutine,返回一個函數,一旦你調用這個函數,就進入coroutine,和create功能重複
coroutine.running()返回正在跑的coroutine,一個coroutine就是一個線程,當使用running的時候,就是返回一個corouting的線程號
function foo(a)
	print("foo 函數輸出 ",a)
	-- 返回2*a的值
	return coroutine.yield(2 * a)
end

co = coroutine.create(function (a,b)
--cp-body 1 10
	print("第一次協同程序執行輸出 ", a,b)
	local r = foo(a + 1)

	print("第二次協同程序輸出 ",r)
--a,b的值爲第一次調用協同程序時傳入
	local r,s = coroutine.yield(a+b, a - b)

	print("第三次協同程序輸出 ",r,s)
	--b的值爲第二次調用協同程序時傳入
	return b,"結束協同程序"
end)

print("---------------分割線---------------");
print("main", coroutine.resume(co,1,10))  --true 4
print("協同程序的狀態: ",coroutine.status(co))


print("---------------分割線---------------");
print("main", coroutine.resume(co,"r"))  --true 4
print("協同程序的狀態: ",coroutine.status(co))

print("---------------分割線---------------");
print("main", coroutine.resume(co,"x","y"))  --true 4
print("協同程序的狀態: ",coroutine.status(co))

print("---------------分割線---------------");
print("main", coroutine.resume(co,"x","y"))  --true 4
print("協同程序的狀態: ",coroutine.status(co))

print("---------------分割線---------------");

wKioL1mpLVLTG860AAE3Imy296w896.jpg-wh_50

以上實例接下如下:

  • 調用resume,將協同程序喚醒,resume操作成功返回true,否則返回false;

  • 協同程序運行;

  • 運行到yield語句;

  • yield掛起協同程序,第一次resume返回;(注意:此處yield返回,參數是resume的參數)

  • 第二次resume,再次喚醒協同程序;(注意:此處resume的參數中,除了第一個參數,剩下的參數將作爲yield的參數)

  • yield返回;

  • 協同程序繼續運行;

  • 如果使用的協同程序繼續運行完成後繼續調用 resume方法則輸出:cannot resume dead coroutine

resume和yield的配合強大之處在於,resume處於主程中,它將外部狀態(數據)傳入到協同程序內部;而yield則將內部的狀態(數據)返回到主程中。

=============================================================================

生產者-消費者問題

現在我就使用Lua的協同程序來完成生產者-消費者這一經典問題。

local newProductor

function productor()
	local i= 0;
	while true do
		i = i + 1;
		send(i) -- 將生產的物品發給消費者
	end
end

function consume()
	i = 0
	while (i < 10) -- 控制大小
	do
		i = i + 1
		local i = receive() --從生產者那裏得到物品
		print(i)
	end
end

function receive()
	local status , value = coroutine.resume(newProductor)
	return value
end

function send(x)
--x表示需要發生的值,值返回以後,就掛起該協同程序
	coroutine.yield(x)
end

-- 啓動程序
newProductor = coroutine.create(productor)
consume()

wKiom1mpMWLyC2ksAACACERWSIw636.jpg-wh_50

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章