Lua非搶占式多執行緒

2021-10-02 21:36:35 字數 4209 閱讀 8320

當乙個協同正在執行時,不能在外部終止他。只能通過顯示的呼叫 yield 掛起他的執行。對於某些應用來說這個不存在問題,但有些應用對此是不能忍受的。不存在搶占式呼叫的程式是容易編寫的。不需要考慮同步帶來的 bugs,因為程式中的所有執行緒間的同步都是顯示的。你僅僅需要在協同**超出臨界區時呼叫 yield 即可。

對非搶占式多執行緒來說,不管什麼時候只要有乙個執行緒呼叫乙個阻塞操作(blocking operation),整個程式在阻塞操作完成之前都將停止。對大部分應用程式而言,只是無法忍受的,這使得很多程式設計師離協同而去。下面我們將看到這個問題可以被有趣的解決。

第一,載入 luasocket 庫

require "luasocket"

host =

"www.w3.org"

file =

"/tr/rec-html32.html"

第三,開啟乙個 tcp 連線到遠端主機的 80 埠(http 服務的標準埠)

c =assert

(socket.

connect

(host,80)

) 上面這句返回乙個連線物件,我們可以使用這個連線物件請求傳送檔案

) receive 函式返回他送接收到的資料加上乙個表示操作狀態的字串。當主機斷開連線時,我們退出迴圈。

第四,關閉連線

c:close

()

使用協同機制重寫上面的**,在乙個函式內:

function download (host, file) 

local c =

assert

(socket.

connect

(host,80)

) local count =

0-- counts number of bytes read

)while

true

do count = count + string.

len(s)

if status ==

"closed" then break end

end

c:close()

print

(file, count)

end

function receive (connection)

return connection:

receive(2

^10) end

在同步接受資料的方式下,函式接收資料時不能被阻塞,而是在沒有資料可取時yield,**如下:

function receive (connection) 

connection:

timeout(0

)--donot block

local s, status = connection:

receive(2

^10)if status ==

"timeout" then

coroutine.

yield

(connection)

end

return s, status

end

呼叫函式 timeout(0)使得對連線的任何操作都不會阻塞。當操作返回的狀態為timeout 時意味著操作未完成就返回了。在這種情況下,執行緒 yield。非 false 的數值作為yield 的引數告訴分配器執行緒仍在執行它的任務。(後面我們將看到分配器需要 timeout連線的情況),注意:即使在 timeout 模式下,連線依然返回他接受到直到 timeout 為止,因此 receive 會一直返回 s 給她的呼叫者。

threads =

-- list of all live threads

function get (host, file)

-- create coroutine

local co = coroutine.

create

(function (

)download

(host, file)

end)

-- insert it in the list

table.

insert

(threads, co)

end

**中 table 中為分配器儲存了所有活動的執行緒。分配器**是很簡單的,它是乙個迴圈,逐個呼叫每乙個執行緒。並且從執行緒列表中

移除已經完成任務的執行緒。當沒有執行緒可以執行時退出迴圈。

function dispatcher (

)while

true

do local n = table.

getn

(threads)

if n ==

0 then break end -- no more threads to run

for i=

1,n do

local status, res = coroutine.

resume

(threads[i])if

not res then -- thread finished its task?

table.

remove

(threads, i)

break

end

end

end

end

host =

"www.w3c.org"

get(host,

"/tr/html401/html40.txt"

)get

(host,

"/tr/2002/rec-xhtml1-20020801/xhtml1.pdf"

)get

(host,

"/tr/rec-html32.html"

)get

(host,

"/tr/2000/rec-dom-level-2-core-20001113/dom2-core.txt"

)dispatcher()

-- main loop

為了避免這種情況出現,我們可以使用 luasocket 庫中的 select 函式。當程式在一組 socket 中不斷的迴圈等待狀態改變時,它可以使程式被阻塞。我們只需要修改分配器,使用 select 函式修改後的**如下:

function dispatcher (

)while

true

do local n = table.

getn

(threads)

if n ==

0 then break end -- no more threads to run

local connections =

for i=

1,n do

local status, res = coroutine.

resume

(threads[i])if

not res then -- thread finished its task?

table.

remove

(threads, i)

break

else

-- timeout

table.

insert

(connections, res)

end

end

if table.

getn

(connections)

== n then

socket.

select

(connections)

end

end

end

在內層的迴圈分配器收集連線表中timeout地連線,注意:receive將連線傳遞給yield,因此 resume 返回他們。當所有的連線都 timeout 分配器呼叫 select 等待任一連線狀態的改變。最終的實現效率和上乙個協同實現的方式相當,另外,他不會發生忙等待,比起順序實現的方式消耗 cpu 的時間僅僅多一點點。

LUA教程非搶占式多執行緒 38

對非搶占式多執行緒來說,不管什麼時候只要有乙個執行緒呼叫乙個阻塞操作 blocking operation 整個程式在阻塞操作完成之前都將停止。對大部分應用程式而言,只是無法忍受的,這使得很多程式設計師離協同而去。下面我們將看到這個問題可以被有趣的解決。require luasocket host ...

執行緒的搶占式和非搶占式排程

在乙個程序裡,執行緒的排程有搶占式或者非搶占的模式。在搶占模式下,作業系統負責分配 時間給各個程序,一旦當前的程序使用完分配給自己的 時間,作業系統將決定下乙個占用 時間的是哪乙個執行緒。因此作業系統將定期的中斷當前正在執行的執行緒,將 分配給在等待佇列的下乙個執行緒。所以任何乙個執行緒都不能獨佔 ...

執行緒的排程有搶占式或者非搶占

在乙個程序裡,執行緒的排程有搶占式或者非搶占的模式。在搶占模式下,作業系統負責分配 時間給各個程序,一旦當前的程序使用完分配給自己的 時間,作業系統將決定下乙個占用 時間的是哪乙個執行緒。因此作業系統將定期的中斷當前正在執行的執行緒,將 分配給在等待佇列的下乙個執行緒。所以任何乙個執行緒都不能獨佔 ...