-
multi v15.1.x Stable
released this
2021-11-30 21:28:18 -05:00 | 152 commits to master since this releaseUpdate 15.1.0 - Hold the thread!
Full Update Showcase
package.path = "./?/init.lua;"..package.path multi,thread = require("multi"):init() func = thread:newFunction(function(count) local a = 0 while true do a = a + 1 thread.sleep(.1) thread.pushStatus(a,count) if a == count then break end end return "Done" end) multi:newThread("Function Status Test",function() local ret = func(10) local ret2 = func(15) local ret3 = func(20) ret.OnStatus(function(part,whole) print("Ret1: ",math.ceil((part/whole)*1000)/10 .."%") end) ret2.OnStatus(function(part,whole) print("Ret2: ",math.ceil((part/whole)*1000)/10 .."%") end) ret3.OnStatus(function(part,whole) print("Ret3: ",math.ceil((part/whole)*1000)/10 .."%") end) -- Connections can now be added together, if you had multiple holds and one finished before others and wasn't consumed it would lock forever! This is now fixed thread.hold(ret2.OnReturn + ret.OnReturn + ret3.OnReturn) print("Function Done!") os.exit() end) test = thread:newFunction(function() return 1,2,nil,3,4,5,6,7,8,9 end,true) print(test()) multi:newThread("testing",function() print("#Test = ",test()) print(thread.hold(function() print("Hello!") return false end,{ interval = 2, cycles = 3 })) -- End result, 3 attempts within 6 seconds. If still false then timeout print("held") end).OnError(function(...) print(...) end) sandbox = multi:newProcessor() sandbox:newTLoop(function() print("testing...") end,1) test2 = multi:newTLoop(function() print("testing2...") end,1) sandbox:newThread("Test Thread",function() local a = 0 while true do thread.sleep(1) a = a + 1 print("Thread Test: ".. multi.getCurrentProcess().Name) if a == 10 then sandbox.Stop() end end end).OnError(function(...) print(...) end) multi:newThread("Test Thread",function() while true do thread.sleep(1) print("Thread Test: ".. multi.getCurrentProcess().Name) end end).OnError(function(...) print(...) end) sandbox.Start() multi:mainloop()Added:
multi:newSystemThreadedJobQueue(n) isEmpty()
- returns true if the queue is empty, false if there are items in the queue.
Note: a queue might be empty, but the job may still be running and not finished yet! Also if a registered function is called directly instead of pushed, it will not reflect inside the queue until the next cycle!
Example:
package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path package.cpath = [[C:\Program Files (x86)\Lua\5.1\systree\lib\lua\5.1\?.dll;C:\Program Files (x86)\Lua\5.1\systree\lib\lua\5.1\?\core.dll;]] ..package.cpath multi,thread = require("multi"):init() GLOBAL,THREAD = require("multi.integration.threading"):init() -- Auto detects your enviroment and uses what's available jq = multi:newSystemThreadedJobQueue(5) -- Job queue with 4 worker threads func = jq:newFunction("test",function(a,b) THREAD.sleep(2) return a+b end) for i = 1,10 do func(i,i*3).connect(function(data) print(data) end) end local a = true b = false multi:newThread("Standard Thread 1",function() while true do thread.sleep(.1) print("Empty:",jq:isEmpty()) end end).OnError(function(self,msg) print(msg) end) multi:mainloop()multi.TIMEOUT
multi.TIMEOUTis equal to "TIMEOUT", it is reccomended to use this incase things change later on. There are plans to change the timeout value to become a custom object instead of a string.new connections on threaded functions
-
func.OnStatus(...)Allows you to connect to the status of a function see thread.pushStatus()
-
func.OnReturn(...)Allows you to connect to the functions return event and capture its returns see Example for an example of it in use.
multi:newProcessor(name)
package.path = "./?/init.lua;"..package.path multi,thread = require("multi"):init() -- Create a processor object, it works a lot like the multi object sandbox = multi:newProcessor() -- On our processor object create a TLoop that prints "testing..." every second sandbox:newTLoop(function() print("testing...") end,1) -- Create a thread on the processor object sandbox:newThread("Test Thread",function() -- Create a counter named 'a' local a = 0 -- Start of the while loop that ends when a = 10 while true do -- pause execution of the thread for 1 second thread.sleep(1) -- increment a by 1 a = a + 1 -- display the name of the current process print("Thread Test: ".. multi.getCurrentProcess().Name) if a == 10 then -- Stopping the processor stops all objects created inside that process including threads. In the backend threads use a regular multiobject to handle the scheduler and all of the holding functions. These all stop when a processor is stopped. This can be really useful to sandbox processes that might need to turned on and off with ease and not having to think about it. sandbox.Stop() end end -- Catch any errors that may come up end).OnError(function(...) print(...) end) sandbox.Start() -- Start the process multi:mainloop() -- The main loop that allows all processes to continueNote: Processor objects have been added and removed many times in the past, but will remain with this update.
Attribute Type Returns Description Start Method() self Starts the process Stop Method() self Stops the process OnError Connection connection Allows connection to the process error handler Type Member: string"process" Contains the type of object Active Member: booleanvariable If false the process is not active Name Member: stringvariable The name set at process creation process Thread thread A handle to a multi thread object Note: All tasks/threads created on a process are linked to that process. If a process is stopped all tasks/threads will be halted until the process is started back up.
Connection can now be added together
Very useful when using thread.hold for multiple connections to trigger.
Iif you had multiple holds and one finished before others and wasn't consumed it would lock forever! This is now fixed
print(conn + conn2 + conn3 + connN)Can be chained as long as you want! See example below
Status added to threaded functions
-
thread.pushStatus(...)Allows a developer to push a status from a function.
-
tFunc.OnStatus(func(...))A connection that can be used on a function to view the status of the threaded function
Example:
package.path = "./?/init.lua;"..package.path multi,thread = require("multi"):init() func = thread:newFunction(function(count) local a = 0 while true do a = a + 1 thread.sleep(.1) thread.pushStatus(a,count) if a == count then break end end return "Done" end) multi:newThread("Function Status Test",function() local ret = func(10) local ret2 = func(15) local ret3 = func(20) ret.OnStatus(function(part,whole) --[[ Print out the current status. In this case every second it will update with: 10% 20% 30% ... 100% Function Done! ]] print(math.ceil((part/whole)*1000)/10 .."%") end) ret2.OnStatus(function(part,whole) print("Ret2: ",math.ceil((part/whole)*1000)/10 .."%") end) ret3.OnStatus(function(part,whole) print("Ret3: ",math.ceil((part/whole)*1000)/10 .."%") end) -- Connections can now be added together, if you had multiple holds and one finished before others and wasn't consumed it would lock forever! This is now fixed thread.hold(ret2.OnReturn + ret.OnReturn + ret3.OnReturn) print("Function Done!") os.exit() end)Changed:
-
f = thread:newFunction(func,holdme)- Nothing changed that will affect how the object functions by default. The returned function is now a table that is callable and 3 new methods have been added:
Method Description Pause() Pauses the function, Will cause the function to return nil, Function is pausedResume() Resumes the function holdMe(set) Sets the holdme argument that existed at function creation package.path = "./?/init.lua;"..package.path multi, thread = require("multi"):init() test = thread:newFunction(function(a,b) thread.sleep(1) return a,b end, true) print(test(1,2)) test:Pause() print(test(1,2)) test:Resume() print(test(1,2)) --[[ -- If you left holdme nil/false print(test(1,2).connect(function(...) print(...) end)) test:Pause() print(test(1,2).connect(function(...) print(...) end)) test:Resume() print(test(1,2).connect(function(...) print(...) end)) ]] multi:mainloop()Output:
1 2 nil Function is paused 1 2If holdme is nil/false:
nil Function is paused 1 2 nil... 1 2 nil... -
thread.hold(n,opt) Ref. Issue
-
Added option table to thread.hold
Option Description interval Time between each poll cycles Number of cycles before timing out sleep Number of seconds before timing out skip Number of cycles before testing again, does not cause a timeout! Note: cycles and sleep options cannot both be used at the same time. Interval and skip cannot be used at the same time either. Cycles take priority over sleep if both are present! HoldFor and HoldWithin can be emulated using the new features. Old functions will remain for backward compatibility.
Using cycles, sleep or interval will cause a timeout; returning nil, multi.TIMEOUT
-
ncan be a number and thread.hold will act like thread.sleep. Whennis a number the option table will be ignored!
-
Removed:
- N/A
Fixed:
- Threaded functions not returning multiple values Ref. Issue
- Priority Lists not containing Very_High and Very_Low from previous update
- All functions that should have chaining now do, reminder all functions that don't return any data return a reference to itself to allow chaining of method calls.
ToDo
- Work on network parallelism (I really want to make this, but time and getting it right is proving much more difficult)
- Work on QOL changes to allow cleaner code like this
Downloads