ลินุกซ์ + MacOS | หน้าต่าง |
---|---|
Effil เป็นไลบรารีแบบมัลติเธรดสำหรับ Lua อนุญาตให้วางไข่เธรดดั้งเดิมและการแลกเปลี่ยนข้อมูลที่ปลอดภัย Effil ได้รับการออกแบบมาเพื่อมอบ API ที่ชัดเจนและเรียบง่ายสำหรับนักพัฒนา lua
Effil รองรับ lua 5.1, 5.2, 5.3 และ LuaJIT ต้องเป็นไปตามข้อกำหนดของคอมไพเลอร์ C ++ 14 ทดสอบกับ GCC 4.9+, clang 3.8 และ Visual Studio 2015
git clone --recursive https://github.com/effil/effil effil
cd effil && mkdir build && cd build
cmake .. && make install
luarocks install effil
ดังที่คุณอาจทราบแล้วว่าไม่มีภาษาสคริปต์มากนักที่รองรับมัลติเธรด จริง (Lua/Python/Ruby และอื่น ๆ มีการล็อคล่ามทั่วโลกหรือที่เรียกว่า GIL) Effil แก้ปัญหานี้ด้วยการรันอินสแตนซ์ Lua VM อิสระในเธรดดั้งเดิมที่แยกจากกัน และจัดเตรียมการสื่อสารพื้นฐานที่มีประสิทธิภาพสำหรับการสร้างเธรดและการแชร์ข้อมูล
ไลบรารี Effil มีบทคัดย่อหลักสามประการ:
effil.thread
- จัดเตรียม API สำหรับการจัดการเธรดeffil.table
- จัดเตรียม API สำหรับการจัดการตาราง สามารถใช้ตารางร่วมกันระหว่างเธรดได้effil.channel
- จัดให้มีคอนเทนเนอร์เข้าก่อนออกก่อนสำหรับการแลกเปลี่ยนข้อมูลตามลำดับและยูทิลิตี้มากมายในการจัดการเธรดและตารางเช่นกัน
local effil = require ( " effil " )
function bark ( name )
print ( name .. " barks from another thread! " )
end
-- run funtion bark in separate thread with name "Spaky"
local thr = effil . thread ( bark )( " Sparky " )
-- wait for completion
thr : wait ()
เอาท์พุต: Sparky barks from another thread!
local effil = require ( " effil " )
-- channel allow to push data in one thread and pop in other
local channel = effil . channel ()
-- writes some numbers to channel
local function producer ( channel )
for i = 1 , 5 do
print ( " push " .. i )
channel : push ( i )
end
channel : push ( nil )
end
-- read numbers from channels
local function consumer ( channel )
local i = channel : pop ()
while i do
print ( " pop " .. i )
i = channel : pop ()
end
end
-- run producer
local thr = effil . thread ( producer )( channel )
-- run consumer
consumer ( channel )
thr : wait ()
เอาท์พุท:
push 1
push 2
pop 1
pop 2
push 3
push 4
push 5
pop 3
pop 4
pop 5
effil = require ( " effil " )
-- effil.table transfers data between threads
-- and behaves like regualr lua table
local storage = effil . table { string_field = " first value " }
storage . numeric_field = 100500
storage . function_field = function ( a , b ) return a + b end
storage . table_field = { fist = 1 , second = 2 }
function check_shared_table ( storage )
print ( storage . string_field )
print ( storage . numeric_field )
print ( storage . table_field . first )
print ( storage . table_field . second )
return storage . function_field ( 1 , 2 )
end
local thr = effil . thread ( check_shared_table )( storage )
local ret = thr : get ()
print ( " Thread result: " .. ret )
เอาท์พุท:
first value
100500
1
2
Thread result: 3
Effil อนุญาตให้ส่งข้อมูลระหว่างเธรด (สถานะล่าม Lua) โดยใช้ effil.channel
, effil.table
หรือโดยตรงเป็นพารามิเตอร์ของ effil.thread
nil
, boolean
, number
, string
lua_dump
ค่าที่เพิ่มขึ้นจะถูกบันทึกตามกฎlua_iscfunction
ส่งคืนค่าจริง) จะถูกส่งโดยตัวชี้โดยใช้ lua_tocfunction
(ใน lua_State ดั้งเดิม) และ lua_pushcfunction (ใน lua_State ใหม่)lua_iscfunction
จะส่งคืน true แต่ lua_tocfunction
จะส่งคืน nullptr ด้วยเหตุนี้เราจึงไม่พบวิธีส่งสัญญาณระหว่าง lua_Stateseffil.table
แบบเรียกซ้ำ ดังนั้นตาราง Lua ใดๆ จะกลายเป็น effil.table
การทำให้เป็นอนุกรมของตารางอาจใช้เวลานานสำหรับตารางขนาดใหญ่ ดังนั้นจึงเป็นการดีกว่าที่จะใส่ข้อมูลโดยตรงไปที่ effil.table
เพื่อหลีกเลี่ยงการทำให้ตารางเป็นอนุกรม ลองพิจารณา 2 ตัวอย่าง: -- Example #1
t = {}
for i = 1 , 100 do
t [ i ] = i
end
shared_table = effil . table ( t )
-- Example #2
t = effil . table ()
for i = 1 , 100 do
t [ i ] = i
end
ในตัวอย่าง #1 เราสร้างตารางปกติ เติมตารางแล้วแปลงเป็น effil.table
ในกรณีนี้ Effil จำเป็นต้องตรวจสอบเขตข้อมูลตารางทั้งหมดอีกครั้ง อีกวิธีหนึ่งคือตัวอย่างที่ 2 โดยที่เราสร้าง effil.table
ขึ้นมาในตอนแรก และหลังจากนั้นเราก็ใส่ข้อมูลไปที่ effil.table
โดยตรง วิธีที่ 2 ค่อนข้างเร็วกว่ามาก ลองทำตามหลักการนี้
การดำเนินการทั้งหมดที่ใช้ตัววัดเวลาสามารถบล็อกหรือไม่บล็อกได้ และใช้ API ต่อไปนี้: (time, metric)
โดยที่ metric
คือช่วงเวลา เช่น 's'
(วินาที) และ time
คือจำนวนช่วงเวลา
ตัวอย่าง:
thread:get()
- รอให้เธรดเสร็จสิ้นอย่างไม่มีที่สิ้นสุดthread:get(0)
- ไม่มีการบล็อกการรับ เพียงตรวจสอบว่าเธรดเสร็จสิ้นและส่งคืนthread:get(50, "ms")
- บล็อกรอ 50 มิลลิวินาทีรายการช่วงเวลาที่ใช้ได้:
ms
- มิลลิวินาที;s
- วินาที (ค่าเริ่มต้น);m
- นาที;h
- ชั่วโมงการดำเนินการบล็อคทั้งหมด (แม้จะอยู่ในโหมดไม่บล็อค) เป็นจุดหยุดชะงัก เธรดที่ค้างในการดำเนินการดังกล่าวสามารถถูกขัดจังหวะได้โดยการเรียกใช้เมธอด thread:cancel()
local effil = require " effil "
local worker = effil . thread ( function ()
effil . sleep ( 999 ) -- worker will hang for 999 seconds
end )()
worker : cancel ( 1 ) -- returns true, cause blocking operation was interrupted and thread was cancelled
การทำงานกับฟังก์ชัน Effil จะทำให้ซีเรียลไลซ์และดีซีเรียลไลซ์พวกมันโดยใช้วิธี lua_dump
และ lua_load
ค่าที่เพิ่มขึ้นของฟังก์ชันทั้งหมดจะถูกจัดเก็บตามกฎเดียวกันตามปกติ หากฟังก์ชันมี ค่าเพิ่มเป็นประเภทที่ไม่รองรับ ฟังก์ชันนี้จะไม่สามารถส่งไปยัง Effil ได้ คุณจะได้รับข้อผิดพลาดในกรณีนี้
การทำงานกับฟังก์ชัน Effil สามารถจัดเก็บสภาพแวดล้อมของฟังก์ชัน ( _ENV
) ได้เช่นกัน เมื่อคำนึงถึงสภาพแวดล้อมเหมือนตารางปกติ Effil จะจัดเก็บในลักษณะเดียวกับตารางอื่นๆ แต่มันไม่สมเหตุสมผลที่จะจัดเก็บ global _G
ดังนั้นจึงมีความเฉพาะเจาะจงบางประการ:
_ENV ~= _G
) effil.thread
สามารถหยุดชั่วคราวและยกเลิกได้โดยใช้วิธีการที่สอดคล้องกันของ thread object thread:cancel()
และ thread:pause()
เธรดที่คุณพยายามขัดจังหวะสามารถถูกขัดจังหวะได้ในสองจุดดำเนินการ: ชัดเจนและโดยนัย
จุดที่ชัดเจนคือ effil.yield()
local thread = effil . thread ( function ()
while true do
effil . yield ()
end
-- will never reach this line
end )()
thread : cancel ()
จุดโดยนัยคือการเรียกใช้ lua debug hook ซึ่งตั้งค่าโดยใช้ lua_sethook กับ LUA_MASKCOUNT
จุดโดยนัยเป็นทางเลือกและเปิดใช้งานเฉพาะในกรณีที่ thread_runner.step > 0
local thread_runner = effil . thread ( function ()
while true do
end
-- will never reach this line
end )
thread_runner . step = 10
thread = thread_runner ()
thread : cancel ()
นอกจากนี้ เธรดยังสามารถยกเลิกได้ (แต่ไม่หยุดชั่วคราว) ในการดำเนินการรอแบบบล็อกหรือไม่บล็อก
local channel = effil . channel ()
local thread = effil . thread ( function ()
channel : pop () -- thread hangs waiting infinitely
-- will never reach this line
end )()
thread : cancel ()
การยกเลิกทำงานอย่างไร?
เมื่อคุณยกเลิกเธรด มันจะสร้าง error
lua พร้อมข้อความ "Effil: thread is cancelled"
เมื่อถึงจุดหยุดชะงัก หมายความว่าคุณสามารถตรวจจับข้อผิดพลาดนี้ได้โดยใช้ pcall
แต่เธรดจะสร้างข้อผิดพลาดใหม่ในจุดหยุดชะงักถัดไป
หากคุณต้องการตรวจจับข้อผิดพลาดของคุณเองแต่ผ่านข้อผิดพลาดในการยกเลิก คุณสามารถใช้ effil.pcall()
สถานะของเธรดที่ถูกยกเลิกจะเท่ากับ cancelled
ก็ต่อเมื่อเสร็จสิ้นโดยมีข้อผิดพลาดในการยกเลิก หมายความว่าหากคุณพบข้อผิดพลาดในการยกเลิกเธรดอาจเสร็จสิ้นด้วยสถานะ completed
หรือสถานะ failed
หากจะมีข้อผิดพลาดอื่นอีก
effil.thread
เป็นวิธีการสร้างเธรด เธรดสามารถหยุด หยุดชั่วคราว ดำเนินการต่อ และยกเลิกได้ การดำเนินการทั้งหมดกับเธรดสามารถเป็นแบบซิงโครนัส (พร้อมตัวเลือกการหมดเวลา) หรือแบบอะซิงโครนัส แต่ละเธรดทำงานโดยมีสถานะ lua ของตัวเอง
ใช้ effil.table
และ effil.channel
เพื่อส่งข้อมูลผ่านเธรด ดูตัวอย่างการใช้เธรดได้ที่นี่
runner = effil.thread(func)
สร้างตัวรันเธรด Runner จะวางเธรดใหม่สำหรับการร้องขอแต่ละครั้ง
อินพุต : func - ฟังก์ชัน Lua
เอาต์พุต : runner - วัตถุตัวรันเธรดเพื่อกำหนดค่าและรันเธรดใหม่
อนุญาตให้กำหนดค่าและเรียกใช้เธรดใหม่
thread = runner(...)
เรียกใช้ฟังก์ชันที่บันทึกพร้อมกับอาร์กิวเมนต์ที่ระบุในเธรดที่แยกจากกัน และส่งคืนหมายเลขอ้างอิงของเธรด
input : อาร์กิวเมนต์จำนวนเท่าใดก็ได้ที่ต้องการโดยฟังก์ชันที่บันทึก
เอาท์พุต : วัตถุตัวจัดการเธรด
runner.path
เป็นค่า Lua package.path
สำหรับสถานะใหม่ ค่าเริ่มต้นสืบทอดสถานะหลักของแบบฟอร์ม package.path
runner.cpath
เป็นค่า Lua package.cpath
สำหรับสถานะใหม่ ค่าเริ่มต้นสืบทอดสถานะแม่ของแบบฟอร์ม package.cpath
runner.step
จำนวนคำสั่ง lua ระหว่างจุดยกเลิก (ซึ่งสามารถหยุดหรือหยุดเธรดได้) ค่าเริ่มต้นคือ 200 หากค่านี้เป็น 0 เธรดจะใช้เฉพาะจุดการยกเลิกที่ชัดเจนเท่านั้น
ตัวจัดการเธรดจัดเตรียม API สำหรับการโต้ตอบกับเธรด
status, err, stacktrace = thread:status()
คืนสถานะเธรด
เอาท์พุท :
status
- ค่าสตริงอธิบายสถานะของเธรด ค่าที่เป็นไปได้คือ: "running", "paused", "cancelled", "completed" and "failed"
err
- ข้อความแสดงข้อผิดพลาด ถ้ามี ค่านี้ถูกระบุเฉพาะในกรณีที่ thread status == "failed"
stacktrace
- stacktrace ของเธรดที่ล้มเหลว ค่านี้ถูกระบุเฉพาะในกรณีที่ thread status == "failed"
เท่านั้น... = thread:get(time, metric)
รอให้เธรดเสร็จสิ้นและส่งกลับผลลัพธ์ของฟังก์ชันหรือไม่ทำอะไรเลยในกรณีที่เกิดข้อผิดพลาด
input : การหมดเวลาการทำงานในแง่ของการวัดเวลา
เอาต์พุต : ผลลัพธ์ของการเรียกใช้ฟังก์ชันที่บันทึกไว้หรือไม่มีอะไรเกิดขึ้นในกรณีที่เกิดข้อผิดพลาด
thread:wait(time, metric)
รอให้เธรดเสร็จสิ้นและส่งคืนสถานะเธรด
input : การหมดเวลาการทำงานในแง่ของการวัดเวลา
เอาท์พุท : ส่งคืนสถานะของเธรด ผลลัพธ์จะเหมือนกับ thread:status()
thread:cancel(time, metric)
ขัดจังหวะการทำงานของเธรด เมื่อฟังก์ชันนี้ถูกเรียกใช้ แฟล็ก 'การยกเลิก' จะถูกตั้งค่าและสามารถหยุดเธรดได้ในอนาคต (แม้หลังจากการเรียกใช้ฟังก์ชันนี้เสร็จสิ้นแล้ว) เพื่อให้แน่ใจว่าเธรดหยุดทำงานแล้ว ให้เรียกใช้ฟังก์ชันนี้โดยมีการหมดเวลาไม่สิ้นสุด การยกเลิกเธรดที่เสร็จแล้วจะไม่ทำอะไรเลยและส่งคืน true
input : การหมดเวลาการทำงานในแง่ของการวัดเวลา
เอาท์พุต : คืนค่า true
หากเธรดหยุดทำงานหรือ false
thread:pause(time, metric)
หยุดเธรดชั่วคราว เมื่อเรียกใช้ฟังก์ชันนี้แล้ว ตั้งค่าสถานะ 'หยุดชั่วคราว' และเธรดสามารถหยุดชั่วคราวได้ในอนาคต (แม้หลังจากการเรียกใช้ฟังก์ชันนี้เสร็จสิ้นแล้ว) เพื่อให้แน่ใจว่าเธรดถูกหยุดชั่วคราว ให้เรียกใช้ฟังก์ชันนี้โดยมีการหมดเวลาไม่สิ้นสุด
input : การหมดเวลาการทำงานในแง่ของการวัดเวลา
เอาท์พุต : คืนค่า true
หากเธรดถูกหยุดชั่วคราวหรือ false
หากเธรดเสร็จสมบูรณ์ฟังก์ชันจะส่งคืน false
thread:resume()
ดำเนินการเธรดที่หยุดชั่วคราวต่อ ฟังก์ชั่นดำเนินการเธรดต่อทันทีหากถูกหยุดชั่วคราว ฟังก์ชั่นนี้ไม่ทำอะไรเลยสำหรับเธรดที่เสร็จสมบูรณ์ ฟังก์ชั่นไม่มีพารามิเตอร์อินพุตและเอาต์พุต
id = effil.thread_id()
ให้ตัวระบุที่ไม่ซ้ำ
เอาท์พุท : ส่งคืน id
สตริงที่ไม่ซ้ำสำหรับเธรด ปัจจุบัน
effil.yield()
จุดยกเลิกที่ชัดเจน ฟังก์ชั่นตรวจสอบ การยกเลิก หรือ หยุด แฟล็กของเธรดปัจจุบัน และหากจำเป็นก็จะดำเนินการที่เกี่ยวข้อง (ยกเลิกหรือหยุดเธรดชั่วคราว)
effil.sleep(time, metric)
ระงับเธรดปัจจุบัน
อินพุต : อาร์กิวเมนต์การวัดเวลา
effil.hardware_threads()
ส่งกลับจำนวนเธรดพร้อมกันที่สนับสนุนโดยการใช้งาน โดยทั่วไปจะส่งต่อค่าจาก std::thread::hardware_concurrency
เอาท์พุต : จำนวนเธรดฮาร์ดแวร์ที่เกิดขึ้นพร้อมกัน
status, ... = effil.pcall(func, ...)
ทำงานในลักษณะเดียวกับ pcall มาตรฐานทุกประการ ยกเว้นว่าจะไม่พบข้อผิดพลาดในการยกเลิกเธรดที่เกิดจากการเรียก thread:cancel()
ป้อนข้อมูล:
เอาท์พุท:
true
หากไม่มีข้อผิดพลาดเกิดขึ้น มิฉะนั้นจะ false
effil.table
เป็นวิธีการแลกเปลี่ยนข้อมูลระหว่างเธรด effil มันทำงานเกือบจะเหมือนกับตาราง lua มาตรฐาน การดำเนินการทั้งหมดกับตารางที่ใช้ร่วมกันนั้นปลอดภัยสำหรับเธรด ตารางที่ใช้ร่วมกันจะจัดเก็บ ประเภทดั้งเดิม (ตัวเลข บูลีน สตริง) ฟังก์ชัน ตาราง light userdata และข้อมูลผู้ใช้ที่อิง Efil ตารางที่แชร์จะไม่เก็บ เธรด lua (coroutines) หรือข้อมูลผู้ใช้โดยพลการ ดูตัวอย่างการใช้งานตารางที่แชร์ได้ที่นี่
ใช้ ตารางที่ใช้ร่วมกันกับตารางปกติ หากคุณต้องการจัดเก็บตารางปกติในตารางที่แชร์ effil จะดัมพ์ตารางต้นทางไปยังตารางที่แชร์ใหม่โดยปริยาย ตารางที่แชร์จะจัดเก็บตารางย่อยเป็นตารางที่แชร์เสมอ
ใช้ ตารางที่ใช้ร่วมกันพร้อมฟังก์ชัน หากคุณจัดเก็บฟังก์ชันไว้ในตารางที่แชร์ effil จะทิ้งฟังก์ชันนี้โดยปริยายและบันทึกเป็นสตริง (และเป็นค่าที่เพิ่ม) ค่า upvalues ของฟังก์ชันทั้งหมดจะถูกบันทึกตามกฎต่อไปนี้
table = effil.table(tbl)
สร้างตารางแชร์ เปล่า ใหม่
input : tbl
- เป็นพารามิเตอร์ ทางเลือก อาจเป็นได้เฉพาะตาราง Lua ปกติเท่านั้น ซึ่งรายการจะถูก คัดลอก ไปยังตารางที่แชร์
เอาท์พุต : อินสแตนซ์ใหม่ของตารางแชร์เปล่า สามารถว่างเปล่าหรือไม่ก็ได้ ขึ้นอยู่กับเนื้อหา tbl
table[key] = value
ตั้งค่าคีย์ใหม่ของตารางด้วยค่าที่ระบุ
ป้อนข้อมูล :
key
- ค่าใดๆ ของประเภทที่รองรับ ดูรายการประเภทที่รองรับvalue
- ค่าใด ๆ ของประเภทที่รองรับ ดูรายการประเภทที่รองรับvalue = table[key]
รับค่าจากตารางด้วยคีย์ที่ระบุ
input : key
- ค่าใดๆ ของประเภทที่รองรับ ดูรายการประเภทที่รองรับ
เอาท์พุท : value
- ค่าใด ๆ ของประเภทที่รองรับ ดูรายการประเภทที่รองรับ
tbl = effil.setmetatable(tbl, mtbl)
ตั้งค่า metatable ใหม่ให้กับตารางที่แชร์ คล้ายกับชุดมาตรฐานที่สามารถกำหนดได้
ป้อนข้อมูล :
tbl
ควรเป็นตารางแชร์ที่คุณต้องการตั้งค่า metatablemtbl
ควรเป็นตารางปกติหรือตารางที่ใช้ร่วมกันซึ่งจะกลายเป็น metatable หากเป็นตารางปกติ effil จะสร้างตารางที่แชร์ใหม่และคัดลอกช่องทั้งหมดของ mtbl
ตั้งค่า mtbl
เท่ากับ nil
เพื่อลบ metatable ออกจากตารางที่แชร์ output : เพียงส่งคืน tbl
ด้วยค่า metatable ใหม่ที่คล้ายกับวิธี Lua setmetatable มาตรฐาน
mtbl = effil.getmetatable(tbl)
ส่งกลับ metatable ปัจจุบัน คล้ายกับ getmetatable มาตรฐาน
input : tbl
ควรเป็นตารางแชร์
เอาท์พุท : ส่งคืน metatable ของตารางที่ใช้ร่วมกันที่ระบุ ตารางที่ส่งคืนจะมีประเภท effil.table
เสมอ metatable เริ่มต้นคือ nil
tbl = effil.rawset(tbl, key, value)
ตั้งค่ารายการตารางโดยไม่ต้องเรียกใช้ metamethod __newindex
คล้ายกับ rawset มาตรฐาน
ป้อนข้อมูล :
tbl
เป็นตารางแชร์key
- คีย์ของตารางที่จะแทนที่ คีย์อาจเป็นประเภทใดก็ได้ที่รองรับvalue
- ค่าที่จะตั้งค่า ค่าสามารถเป็นประเภทใดก็ได้ที่รองรับ เอาท์พุท : ส่งคืนตารางที่แชร์เหมือนกัน tbl
value = effil.rawget(tbl, key)
รับค่าตารางโดยไม่ต้องเรียกใช้ metamethod __index
คล้ายกับวัตถุดิบมาตรฐาน
ป้อนข้อมูล :
tbl
เป็นตารางแชร์key
- คีย์ของตารางเพื่อรับค่าเฉพาะ คีย์อาจเป็นประเภทใดก็ได้ที่รองรับ เอาท์พุท : ส่งคืน value
ที่ต้องการซึ่งเก็บไว้ภายใต้ key
ที่ระบุ
effil.G
เป็นตารางที่ใช้ร่วมกันที่กำหนดไว้ล่วงหน้าทั่วโลก ตารางนี้จะปรากฏในเธรดใด ๆ เสมอ (สถานะ Lua ใด ๆ )
effil = require " effil "
function job ()
effil = require " effil "
effil . G . key = " value "
end
effil . thread ( job )(): wait ()
print ( effil . G . key ) -- will print "value"
result = effil.dump(obj)
Truns effil.table
ลงในตาราง Lua ปกติ
tbl = effil . table ({})
effil . type ( tbl ) -- 'effil.table'
effil . type ( effil . dump ( tbl )) -- 'table'
effil.channel
เป็นวิธีการแลกเปลี่ยนข้อมูลตามลำดับระหว่างเธรด effil อนุญาตให้พุชข้อความจากเธรดหนึ่งและป๊อปอัปจากอีกเธรดหนึ่ง ข้อความ ของ Channel คือชุดค่าประเภทที่รองรับ การดำเนินการทั้งหมดกับช่องสัญญาณนั้นปลอดภัยสำหรับเธรด ดูตัวอย่างการใช้งานช่องได้ที่นี่
channel = effil.channel(capacity)
จะสร้างช่องใหม่
อินพุต : ความจุ เสริมของช่อง หาก capacity
เท่ากับ 0
หรือ nil
ขนาดของช่องไม่จำกัด กำลังการผลิตเริ่มต้นคือ 0
เอาท์พุท : ส่งคืนอินสแตนซ์ใหม่ของช่อง
pushed = channel:push(...)
ส่งข้อความไปที่ช่อง
input : ค่าใด ๆ ของประเภทที่รองรับ ค่าหลายค่าถือเป็นข้อความช่องเดียว ดังนั้น การกด ไปที่ช่องเดียวจะลดความจุลงหนึ่งรายการ
เอาต์พุต : pushed
จะเท่ากับ true
หากค่า (-s) เหมาะสมกับความจุของช่องสัญญาณ หากเป็นอย่างอื่นจะเป็น false
... = channel:pop(time, metric)
ข้อความป๊อปจากช่อง ลบค่าออกจากช่องและส่งคืน หากช่องว่างเปล่า ให้รอจนกว่าค่าใดๆ จะปรากฏขึ้น
อินพุต : การหมดเวลารอในแง่ของการวัดเวลา (ใช้เฉพาะในกรณีที่ช่องว่างเปล่า)
output : จำนวนตัวแปรของค่าที่ถูกพุชโดยการเรียก single channel:push()
size = channel:size()
รับข้อความตามจำนวนจริงในช่อง
เอาท์พุท : จำนวนข้อความในช่อง
Effil จัดเตรียมตัวรวบรวมขยะแบบกำหนดเองสำหรับ effil.table
และ effil.channel
(และฟังก์ชันที่มีค่า upvalues ที่บันทึกไว้) ช่วยให้จัดการการอ้างอิงแบบวนได้อย่างปลอดภัยสำหรับตารางและช่องสัญญาณในหลายเธรด อย่างไรก็ตาม อาจทำให้เกิดการใช้หน่วยความจำเพิ่มเติมได้ effil.gc
จัดเตรียมชุดของวิธีการกำหนดค่าตัวรวบรวมขยะ effil แต่โดยปกติแล้วคุณไม่จำเป็นต้องกำหนดค่ามัน
ตัวรวบรวมขยะจะดำเนินการเมื่อ effil สร้างอ็อบเจ็กต์ที่แชร์ใหม่ (ตาราง แชนเนล และฟังก์ชันที่มีค่า upvalues ที่บันทึกไว้) GC การวนซ้ำแต่ละครั้งจะตรวจสอบจำนวนอ็อบเจ็กต์ หากจำนวนอ็อบเจ็กต์ที่ได้รับการจัดสรรสูงขึ้น ค่าเกณฑ์เฉพาะ GC จะเริ่มการรวบรวมขยะ ค่าเกณฑ์จะคำนวณเป็น previous_count * step
โดยที่ previous_count
- จำนวนอ็อบเจ็กต์ในการวนซ้ำครั้งก่อนหน้า ( 100 โดยค่าเริ่มต้น) และ step
คือสัมประสิทธิ์ตัวเลขที่ระบุโดยผู้ใช้ ( 2.0 โดยค่าเริ่มต้น)
ตัวอย่างเช่น หาก step
GC คือ 2.0
และจำนวนอ็อบเจ็กต์ที่จัดสรรคือ 120
(เหลือหลังจากการวนซ้ำ GC ครั้งก่อน) GC จะเริ่มรวบรวมขยะเมื่อจำนวนอ็อบเจ็กต์ที่จัดสรรจะเท่ากับ 240
แต่ละเธรดจะแสดงเป็นสถานะ Lua ที่แยกจากกันโดยมีตัวรวบรวมขยะของตัวเอง ดังนั้นวัตถุจะถูกลบในที่สุด ออบเจ็กต์ Effil เองก็จัดการโดย GC และใช้เมตาเมธอดข้อมูลผู้ใช้ __gc
เป็น hook deserializer หากต้องการบังคับให้ลบออบเจ็กต์:
collectgarbage()
ในทุกเธรดeffil.gc.collect()
ในเธรดใดก็ได้effil.gc.collect()
บังคับให้รวบรวมขยะ อย่างไรก็ตาม ไม่ได้รับประกันการลบออบเจ็กต์ที่มีผลทั้งหมด
count = effil.gc.count()
แสดงจำนวนตารางและช่องที่ใช้ร่วมกันที่จัดสรร
output : ส่งคืนจำนวนอ็อบเจ็กต์ที่จัดสรรในปัจจุบัน ค่าต่ำสุดคือ 1 โดย effil.G
จะแสดงอยู่เสมอ
old_value = effil.gc.step(new_value)
รับ/ตั้งค่าตัวคูณขั้นตอนหน่วยความจำ GC ค่าเริ่มต้นคือ 2.0
GC ทริกเกอร์การรวบรวมเมื่อจำนวนอ็อบเจ็กต์ที่จัดสรรเพิ่มขึ้นตามเวลา step
input : new_value
คือค่าทางเลือกของขั้นตอนที่จะตั้งค่า หากเป็น nil
ฟังก์ชันก็จะส่งคืนค่าปัจจุบัน
เอาต์พุต : old_value
เป็นค่าปัจจุบัน (ถ้า new_value == nil
) หรือค่าก่อนหน้า (ถ้า new_value ~= nil
) ของขั้นตอน
effil.gc.pause()
หยุด GC ชั่วคราว การเก็บขยะจะไม่ดำเนินการโดยอัตโนมัติ ฟังก์ชั่นไม่มี อินพุต หรือ เอาต์พุต ใดๆ
effil.gc.resume()
ดำเนินการต่อ GC เปิดใช้งานการรวบรวมขยะอัตโนมัติ
enabled = effil.gc.enabled()
รับสถานะ GC
เอาท์พุต : คืนค่า true
หากเปิดใช้งานการรวบรวมขยะอัตโนมัติหรือเป็น false
โดยค่าเริ่มต้นจะคืนค่า true
size = effil.size(obj)
ส่งกลับจำนวนของรายการในวัตถุ Effil
input : obj
คือตารางหรือช่องที่แชร์
เอาท์พุท : จำนวนรายการในตารางที่แชร์หรือจำนวนข้อความในช่อง
type = effil.type(obj)
เธรด ช่อง และตารางเป็นข้อมูลผู้ใช้ ดังนั้น type()
จะส่งคืน userdata
สำหรับประเภทใดก็ได้ หากคุณต้องการตรวจจับประเภทได้แม่นยำยิ่งขึ้น ให้ใช้ effil.type
มันทำงานเหมือนปกติ type()
แต่สามารถตรวจจับข้อมูลผู้ใช้ที่เฉพาะเจาะจงได้
input : obj
เป็นวัตถุประเภทใดก็ได้
เอาท์พุท : ชื่อสตริงของประเภท หาก obj
เป็นอ็อบเจ็กต์ Effil ฟังก์ชันจะส่งกลับสตริงเช่น effil.table
ในกรณีอื่นๆ จะส่งกลับผลลัพธ์ของฟังก์ชัน lua_typename
effil . type ( effil . thread ()) == " effil.thread "
effil . type ( effil . table ()) == " effil.table "
effil . type ( effil . channel ()) == " effil.channel "
effil . type ({}) == " table "
effil . type ( 1 ) == " number "