協程的乙個經典問題就是生產者-消費者問題。在生產者-消費者問題中涉及兩個函式,乙個函式不斷地產生值(比如,從乙個檔案中讀取),另乙個函式不斷地消費這些值(比如,將值寫入另乙個檔案中)。
function producer ()
while true do
local x = io.read()
send(x)
endendfunction consumer()
while true do
local x = receive()
io.write(x, "\n")
endend
我們的問題在於要如何將send和receive匹配起來,也就是「誰佔據主迴圈」問題的典型例項。其中,生產者和消費者都處於活躍狀態,它們各自擁有自己的主迴圈,並且都將對方視為乙個可呼叫的服務。
由於成對的resume-yield可以顛倒呼叫者與被呼叫者之間的關係,因此協程提供了一種無需修改生產者和消費者的**結構就能匹配它們執行順序的理想工具。 當乙個協程呼叫yield函式時,它不是進入了乙個新的函式,而是返回乙個掛起的呼叫(呼叫的是函式resume)。同樣地,對函式resume的呼叫也不會啟動乙個新的函式,而是返回乙個對函式yield的呼叫。這種特性恰好可以用於匹配send和receive,使得雙方都認為自己是主動方而對方是被動方。因此,receive喚醒生產者的執行使其能產生乙個新值,然後send則讓出執行權,將生成的值傳遞給消費者:
function receive ()
local status, value = coroutine.resume(producer)
return value
endfunction send (x)
coroutine.yield(x)
end
在這種設計中,程式通過呼叫消費者啟動。每當消費者需要新值時就呼叫喚醒生產者,生產者向消費者返回新值後掛起,直到消費者再次將其喚醒。因此,我們將這種設計成為消費者驅動(consumer-driven)式的設計。另乙個方式則是使用生產者驅動的設計。雖然兩種設計思路看上去截然相反,但實際上它們的整體思想相同。
我們可以通過過濾器來擴充套件上述設計。過濾器位於生產者和消費者之間,用於完成一些對資料進行某種變換的任務。過濾器即是乙個消費者又是乙個生產者,它通過喚醒乙個生產者來獲得新值,然後又將變換後的值傳遞給消費者。
function receive (prod)
local status, value = coroutine.resume(prod)
return value
endfunction send (x)
coroutine.yield(x)
endfunction producer ()
return coroutine.create(function ()
while true do
local x = io.read()
send(x)
endend)
endfunction filter (prod)
return coroutine.create(function ()
for line = 1,math.huge do
local x = receive(prod)
x = string.format('%5d %s", line, x)
send(x)
endend)
endfunction consumer (prod)
while true do
local x = receive(prod)
io.write(x,"\n")
endendconsumer(filter(producer))
題解六十七
輸入乙個整數陣列,實現乙個函式來調整該陣列中數字的順序,使得所有奇數字於陣列的前半部分,所有偶數字於陣列的後半部分。示例 輸入 nums 1,2,3,4 輸出 1,3,2,4 注 3,1,2,4 也是正確的答案之一。思路 定義雙指標left right,分別指向陣列的首部和尾部。指標left從左向右...
CUDA學習(六十七)
數學函式 參考手冊列表及其說明列出了裝置 支援的c c 標準庫數學函式的所有功能,以及所有固有功能 僅在裝置 中支援 標準函式 本節中的功能可用於主機和裝置 本節規定了每個功能在裝置上執行時的錯誤界限,以及在主機不提供功能的情況下在主機上執行時的錯誤界限。加法和乘法符合ieee標準,因此最大誤差為0...
六十七課 經典問題解析五
1 編寫程式判斷乙個變數是不是指標 過載函式 函式模板 變參函式 2 思路 示例 指標判斷 include include using namespace std class test virtual test template char isptr t v int isptr define isp...