• rayaman released this 2022-04-19 18:45:14 -04:00 | 0 commits to v15.2.0 since this release

    Update 15.2.1 - Bug Fix

    • Fixed issue

    Update 15.2.0 - Upgrade Complete

    Full Update Showcase

    package.path = "./?/init.lua;"..package.path
    multi, thread = require("multi"):init{print=true}
    GLOBAL, THREAD = require("multi.integration.threading"):init()
    
    -- Using a system thread, but both system and local threads support this!
    -- Don't worry if you don't have lanes or love2d. PesudoThreading will kick in to emulate the threading features if you do not have access to system threading.
    func = THREAD:newFunction(function(count)
    	print("Starting Status test: ",count)
    	local a = 0
    	while true do
    		a = a + 1
    		THREAD.sleep(.1)
    		-- Push the status from the currently running threaded function to the main thread
    		THREAD.pushStatus(a,count)
    		if a == count then break end
    	end
    	return "Done"
    end)
    
    thread:newThread("test",function()
    	local ret = func(10)
    	ret.OnStatus(function(part,whole)
    		print("Ret1: ",math.ceil((part/whole)*1000)/10 .."%")
    	end)
    	print("TEST",func(5).wait())
    	-- The results from the OnReturn connection is passed by thread.hold
    	print("Status:",thread.hold(ret.OnReturn))
    	print("Function Done!")
    end).OnError(function(...)
    	print("Error:",...)
    end)
    
    local ret = func(10)
    local ret2 = func(15)
    local ret3 = func(20)
    local s1,s2,s3 = 0,0,0
    ret.OnError(function(...)
    	print("Error:",...)
    end)
    ret2.OnError(function(...)
    	print("Error:",...)
    end)
    ret3.OnError(function(...)
    	print("Error:",...)
    end)
    ret.OnStatus(function(part,whole)
    	s1 = math.ceil((part/whole)*1000)/10
    	print(s1)
    end)
    ret2.OnStatus(function(part,whole)
    	s2 = math.ceil((part/whole)*1000)/10
    	print(s2)
    end)
    ret3.OnStatus(function(part,whole)
    	s3 = math.ceil((part/whole)*1000)/10
    	print(s3)
    end)
    
    loop = multi:newTLoop()
    
    function loop:testing()
    	print("testing haha")
    end
    
    loop:Set(1)
    t = loop:OnLoop(function()
    	print("Looping...")
    end):testing()
    
    local proc = multi:newProcessor("Test")
    local proc2 = multi:newProcessor("Test2")
    local proc3 = proc2:newProcessor("Test3")
    proc.Start()
    proc2.Start()
    proc3.Start()
    proc:newThread("TestThread_1",function()
    	while true do
    		thread.sleep(1)
    	end
    end)
    proc:newThread("TestThread_2",function()
    	while true do
    		thread.sleep(1)
    	end
    end)
    proc2:newThread("TestThread_3",function()
    	while true do
    		thread.sleep(1)
    	end
    end)
    
    thread:newThread(function()
    	thread.sleep(1)
    	local tasks = multi:getStats()
    
    	for i,v in pairs(tasks) do
    		print("Process: " ..i.. "\n\tTasks:")
    		for ii,vv in pairs(v.tasks) do
    			print("\t\t"..vv:getName())
    		end
    		print("\tThreads:")
    		for ii,vv in pairs(v.threads) do
    			print("\t\t"..vv:getName())
    		end
    	end
    
    	thread.sleep(10) -- Wait 10 seconds then kill the process!
    	os.exit()
    end)
    
    multi:mainloop()
    

    Added:

    • multi:getStats()

      • Returns a structured table where you can access data on processors there tasks and threads:
        -- Upon calling multi:getStats() the table below is returned
        get_Stats_Table {
        	proc_1 -- table
        	proc_2 -- table
        	...
        	proc_n -- table
        }
        proc_Table {
        	tasks = {alarms,steps,loops,etc} -- All multi objects
        	threads = {thread_1,thread_2,thread_3,etc} -- Thread objects
        }
        -- Refer to the objects documentation to see how you can interact with them
        
      • Reference the Full update showcase for the method in action
    • multi:newProcessor(name, nothread)

      • If no thread is true auto sets the processor as Active, so proc.run() will start without the need for proc.Start()
    • multi:getProcessors()

      • Returns a list of all processors
    • multi:getName()

      • Returns the name of a processor
    • multi:getFullName()

      • Returns the fullname/entire process tree of a process
    • Processors can be attached to processors

    • multi:getTasks()

      • Returns a list of all non thread based objects (loops, alarms, steps, etc)
    • multi:getThreads()

      • Returns a list of all threads on a process
    • multi:newProcessor(name, nothread).run()

      • New function run to the processor object to
    • multi:newProcessor(name, nothread):newFunction(func, holdme)

      • Acts like thread:newFunction(), but binds the execution of that threaded function to the processor
    • multi:newTLoop() member functions

      • TLoop:Set(set) - Sets the time to wait for the TLoop
    • multi:newStep() member functions

      • Step:Count(count) - Sets the amount a step should count by
    • multi:newTStep() member functions

      • TStep:Set(set) - Sets the time to wait for the TStep

    Changed:

    • thread.hold(connectionObj) now passes the returns of that connection to thread.hold()! See Exampe below:

      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", 1, 2, 3
      end)
      
      thread:newThread("test",function()
      	local ret = func(10)
      	ret.OnStatus(function(part,whole)
      		print("Ret1: ",math.ceil((part/whole)*1000)/10 .."%")
      	end)
      	print("Status:",thread.hold(ret.OnReturn))
      	print("Function Done!")
      	os.exit()
      end).OnError(function(...)
      	print("Error:",...)
      end)
      
      multi:mainloop()
      

      Output:

      Ret1:   10%
      Ret1:   20%
      Ret1:   30%
      Ret1:   40%
      Ret1:   50%
      Ret1:   60%
      Ret1:   70%
      Ret1:   80%
      Ret1:   90%
      Ret1:   100%
      Status: Done    1       2       3       nil     nil     nil     nil     nil     nil     nil     nil     nil     nil     nil     nil
      Function Done!
      
    • Modified how threads are handled internally. This changes makes it so threads "regardless of amount" should not impact performance. What you do in the threads might. This change was made by internally only processing one thread per step per processor. If you have 10 processors that are all active expect one step to process 10 threads. However if one processor has 10 threads each step will only process one thread. Simply put each addition of a thread shouldn't impact performance as it did before.

    • Moved multi:newThread(...) into the thread interface (thread:newThread(...)), code using multi:newThread(...) will still work. Also using process:newThread(...) binds the thread to the process, meaning if the process the thread is bound to is paused so is the thread.

    • multi:mainloop(settings)/multi:uManager(settings) no longer takes a settings argument, that has been moved to multi:init(settings)

      Setting Description
      print When set to true parts of the library will print out updates otherwise no internal printing will be done
      priority When set to true, the library will prioritize different objects based on their priority
    • multi:newProcessor(name,nothread) The new argument allows you to tell the system you won't be using the Start() and Stop() functions, rather you will handle the process yourself. Using the proc.run() function. This function needs to be called to pump the events.

      • Processors now also use lManager instead of uManager.
    • multi.hold(n,opt) now supports an option table like thread.hold does.

    • Connection Objects now pass on the parent object if created on a multiobj. This was to allow chaining to work properly with the new update

      multi,thread = require("multi"):init()
      
      loop = multi:newTLoop()
      
      function loop:testing()
      	print("testing haha")
      end
      
      loop:Set(1)
      t = loop:OnLoop(function()
      	print("Looping...")
      end):testing()
      
      multi:mainloop()
      
      --[[Returns as expected:
      
      	testing haha
      	Looping...
      	Looping...
      	Looping...
      	...
      	Looping...
      	Looping...
      	Looping...
      ]]
      

      While chaining on the OnSomeEventMethod() wasn't really a used feature, I still wanted to keep it just incase someone was relying on this working. And it does have it uses

    • All Multi Objects now use Connection objects

      multiobj:OnSomeEvent(func) or multiobj.OnSomeEvent(func)

    • Connection Objects no longer Fire with syntax sugar when attached to an object:

      multiobj:OnSomeEvent(...) No longer triggers the Fire event. As part of the update to make all objects use connections internally this little used feature had to be scrapped!

    • multi:newTStep now derives it's functionality from multi:newStep (Cut's down on code length a bit)

    Removed:

    • multi:getTasksDetails() Remade completely and now called multi:getStats()

    • multi:getError() Removed when setting protect was removed

    • multi:FreeMainEvent() The new changes with connections make's this function unnecessary

    • multi:OnMainConnect(func) See above

    • multi:connectFinal(func) See above

    • multi:lightloop() Cleaned up the mainloop/uManager method, actually faster than lightloop (Which should have been called liteloop)

    • multi:threadloop() See above for reasons

    • multi setting: protect This added extra complexity to the mainloop and not much benefit. If you feel a function will error use pcall yourself. This saves a decent amount of cycles, about 6.25% increase in performance.

    • multi:GetParentProcess() use multi.getCurrentProcess() instead

    • priority scheme 2, 3 and auto-priority have been removed! Only priority scheme 1 actually performed in a reasonable fashion so that one remained.

    • multi:newFunction(func)

      • thread:newFunction(func) Has many more features and replaces what multi:newFunction did
    • multi.holdFor() Now that multi.hold takes the option table that thread.hold has this feature can be emulated using that.

    • Calling Fire on a connection no longer returns anything! Now that internal features use connections, I noticed how slow connections are and have increased their speed quite a bit. From 50,000 Steps per seconds to almost 7 Million. All other features should work just fine. Only returning values has been removed

    Fixed:

    • Issue with Lanes crashing the lua state. Issue seemed to be related to my filesystem, since remounting the drive caused the issue to stop. (Windows)

    • Issue where System threaded functions not being up to date with threaded functions

    • Issue where gettasksdetails() would try to process a destroyed object causing it to crash

    • Issue with multi.hold() not pumping the mainloop and only the scheduler

    ToDo:

    • Work on network parallelism
    Downloads