Working on performance

This commit is contained in:
Ryan Ward 2022-01-04 18:01:02 -05:00
parent b74a6c006e
commit 537dcf0db1
4 changed files with 96 additions and 77 deletions

View File

@ -71,22 +71,23 @@ Changed:
- multi:newTStep now derives it's functionality from multi:newStep (Cut's down on code length a bit) - multi:newTStep now derives it's functionality from multi:newStep (Cut's down on code length a bit)
- - Fixed the getTaskDetails to handle the new format for threads
### Developer Note: ### Developer Note:
Connections are some of the most complex objects that this library has outside of some of the system threaded stuff. I tend to add features to connection objects quite often. Just last update connections can be "added" together creating a temp connection that only triggers when all of the added connections got triggered as well. Thinking about the possibilities this could give developers using the library I had to changed the base classes to use connections. Connections are one of the most complex objects that this library has outside of some of the system threaded stuff. I tend to add features to connection objects quite often. Just last update connections can be "added" together creating a temp connection that only triggers when all of the added connections got triggered as well. Thinking about the possibilities this could give developers using the library I had to changed the base classes to use connections.
The best part about this is that connections allow for greater control over an object's events. You can add and remove events that have been connected to as well as a lot of other things. Reference the documentation [here](./Documentation.md#non-actor-connections) The best part about this is that connections allow for greater control over an object's events. You can add and remove events that have been connected to as well as a lot of other things. Reference the documentation [here](./Documentation.md#non-actor-connections)
Removed: Removed:
--- ---
Nothing
- 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: Fixed:
--- ---
- [Issue](https://github.com/rayaman/multi/issues/30) with Lanes crashing the lua state. Fixed it with pcall - [Issue](https://github.com/rayaman/multi/issues/30) with Lanes crashing the lua state. Issue seems to be related to my filesystem
- [Issue](https://github.com/rayaman/multi/issues/29) where System threaded functions not up to date with threaded functions - [Issue](https://github.com/rayaman/multi/issues/29) where System threaded functions not up to date with threaded functions
ToDo: ToDo:

View File

@ -201,6 +201,7 @@ end
local ignoreconn = true local ignoreconn = true
function multi:newConnection(protect,func,kill) function multi:newConnection(protect,func,kill)
local c={} local c={}
local call_funcs = {}
c.callback = func c.callback = func
c.Parent=self c.Parent=self
c.lock = false c.lock = false
@ -245,8 +246,8 @@ function multi:newConnection(protect,func,kill)
c.Type='connector' c.Type='connector'
c.func={} c.func={}
c.ID=0 c.ID=0
c.protect=protect or true c.protect=protect or false
c.connections={} local connections={}
c.FC=0 c.FC=0
function c:holdUT(n) function c:holdUT(n)
local n=n or 0 local n=n or 0
@ -267,9 +268,9 @@ function multi:newConnection(protect,func,kill)
c.HoldUT=c.holdUT c.HoldUT=c.holdUT
function c:getConnection(name,ignore) function c:getConnection(name,ignore)
if ignore then if ignore then
return self.connections[name] or CRef return connections[name] or CRef
else else
return self.connections[name] or self return connections[name] or self
end end
end end
function c:Lock() function c:Lock()
@ -280,51 +281,58 @@ function multi:newConnection(protect,func,kill)
c.lock = false c.lock = false
return self return self
end end
function c:Fire(...) if c.protect then
local ret={} function c:Fire(...)
if self.lock then return end if self.lock then return end
for i=#self.func,1,-1 do for i=#call_funcs,1,-1 do
if self.protect then if not call_funcs[i] then return end
if not self.func[i] then return end pcall(call_funcs[i],...)
local temp={pcall(self.func[i][1],...)} if kill then
if temp[1] then table.remove(call_funcs,i)
table.remove(temp,1)
table.insert(ret,temp)
else
multi.print(temp[2])
end end
else
if not self.func[i] then return end
table.insert(ret,{self.func[i][1](...)})
end
if kill then
table.remove(self.func,i)
end end
end end
return ret else
function c:Fire(...)
for i=#call_funcs,1,-1 do
call_funcs[i](...)
if kill then
table.remove(call_funcs,i)
end
end
end
end
local fast = {}
function c:fastMode()
function self:Fire(...)
for i=1,#fast do
fast[i](...)
end
end
function self:connect(func)
table.insert(fast,func)
end
end end
function c:Bind(t) function c:Bind(t)
local temp = self.func local temp = call_funcs
self.func=t call_funcs=t
return temp return temp
end end
function c:Remove() function c:Remove()
local temp = self.func local temp = call_funcs
self.func={} call_funcs={}
return temp return temp
end end
local function conn_helper(self,func,name,num) local function conn_helper(self,func,name,num)
self.ID=self.ID+1 self.ID=self.ID+1
if num then if num then
table.insert(self.func,num,{func,self.ID}) table.insert(call_funcs,num,func)
else else
table.insert(self.func,1,{func,self.ID}) table.insert(call_funcs,1,func)
end end
local temp = { local temp = {
Link=self.func,
func=func, func=func,
Type="connector_link", Type="connector_link",
ID=self.ID,
Parent=self, Parent=self,
connect = function(s,...) connect = function(s,...)
return self:connect(...) return self:connect(...)
@ -350,29 +358,27 @@ function multi:newConnection(protect,func,kill)
function temp:Fire(...) function temp:Fire(...)
if self.Parent.lock then return end if self.Parent.lock then return end
if self.Parent.protect then if self.Parent.protect then
local t=pcall(self.func,...) local t=pcall(call_funcs,...)
if t then if t then
return t return t
end end
else else
return self.func(...) return call_funcs(...)
end end
end end
function temp:Destroy() function temp:Destroy()
for i=1,#self.Link do for i=1,#call_funcs do
if self.Link[i][2]~=nil then if call_funcs[i]~=nil then
if self.Link[i][2]==self.ID then if call_funcs[i]==self.func then
table.remove(self.Link,i) table.remove(call_funcs,i)
self.remove=function() end self.remove=function() end
self.Link=nil
self.ID=nil
multi.setType(temp,multi.DestroyedObj) multi.setType(temp,multi.DestroyedObj)
end end
end end
end end
end end
if name then if name then
self.connections[name]=temp connections[name]=temp
end end
if self.callback then if self.callback then
self.callback(temp) self.callback(temp)
@ -396,7 +402,6 @@ function multi:newConnection(protect,func,kill)
else else
return conn_helper(self,tab[1],tab[2],tab[3]) return conn_helper(self,tab[1],tab[2],tab[3])
end end
end end
c.Connect=c.connect c.Connect=c.connect
c.GetConnection=c.getConnection c.GetConnection=c.getConnection
@ -711,9 +716,14 @@ function multi:newLoop(func)
self.OnLoop:Fire(self,clock()-start) self.OnLoop:Fire(self,clock()-start)
end end
c.OnLoop = self:newConnection() c.OnLoop = self:newConnection()
function c:fastMode()
self.OnLoop:fastMode()
end
if func then if func then
c.OnLoop(func) c.OnLoop(func)
end end
multi:create(c) multi:create(c)
return c return c
end end
@ -978,9 +988,9 @@ function thread.getRunningThread()
local threads = globalThreads local threads = globalThreads
local t = coroutine.running() local t = coroutine.running()
if t then if t then
for i,v in pairs(threads) do for th,process in pairs(threads) do
if t==i.thread then if t==th.thread then
return v return th
end end
end end
end end
@ -1204,16 +1214,16 @@ function thread:newFunctionBase(generator,holdme)
return wait() return wait()
end end
local temp = { local temp = {
OnStatus = multi:newConnection(), OnStatus = multi:newConnection(true),
OnError = multi:newConnection(), OnError = multi:newConnection(true),
OnReturn = multi:newConnection(), OnReturn = multi:newConnection(true),
isTFunc = true, isTFunc = true,
wait = wait, wait = wait,
getReturns = function() getReturns = function()
return unpack(rets) return unpack(rets)
end, end,
connect = function(f) connect = function(f)
local tempConn = multi:newConnection() local tempConn = multi:newConnection(true)
t.OnDeath(function(self,status,...) if f then f(...) else tempConn:Fire(...) end end) t.OnDeath(function(self,status,...) if f then f(...) else tempConn:Fire(...) end end)
t.OnError(function(self,err) if f then f(nil,err) else tempConn:Fire(nil,err) end end) t.OnError(function(self,err) if f then f(nil,err) else tempConn:Fire(nil,err) end end)
return tempConn return tempConn
@ -2291,17 +2301,14 @@ function multi:benchMark(sec,p,pt)
if pt then if pt then
multi.print(pt.." "..c.." Steps in "..sec.." second(s)!") multi.print(pt.." "..c.." Steps in "..sec.." second(s)!")
end end
self.tt(sec,c) self.OnBench:Fire(sec,c)
self:Destroy() self:Destroy()
else else
c=c+1 c=c+1
end end
end) end)
temp.OnBench = multi:newConnection()
temp:setPriority(p or 1) temp:setPriority(p or 1)
function temp:OnBench(func)
self.tt=func
end
self.tt=function() end
return temp return temp
end end

View File

@ -21,6 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
package.path = "?/init.lua;?.lua;" .. package.path package.path = "?/init.lua;?.lua;" .. package.path
multi, thread = require("multi"):init() -- get it all and have it on all lanes multi, thread = require("multi"):init() -- get it all and have it on all lanes
if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassle if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassle
@ -31,7 +32,7 @@ if multi.integration then -- This allows us to call the lanes manager from suppo
} }
end end
-- Step 1 get lanes -- Step 1 get lanes
lanes = require("lanes").configure({allocator="protected",verbose_errors=""}) lanes = require("lanes").configure()
multi.SystemThreads = {} multi.SystemThreads = {}
multi.isMainThread = true multi.isMainThread = true
@ -47,12 +48,6 @@ end
local __GlobalLinda = lanes.linda() -- handles global stuff local __GlobalLinda = lanes.linda() -- handles global stuff
local __SleepingLinda = lanes.linda() -- handles sleeping stuff local __SleepingLinda = lanes.linda() -- handles sleeping stuff
local __ConsoleLinda = lanes.linda() -- handles console stuff local __ConsoleLinda = lanes.linda() -- handles console stuff
multi:newLoop(function()
local _,data = __ConsoleLinda:receive(0, "Q")
if data then
print(unpack(data))
end
end)
local GLOBAL,THREAD = require("multi.integration.lanesManager.threads").init(__GlobalLinda,__SleepingLinda) local GLOBAL,THREAD = require("multi.integration.lanesManager.threads").init(__GlobalLinda,__SleepingLinda)
local count = 1 local count = 1
local started = false local started = false
@ -65,6 +60,7 @@ function THREAD:newFunction(func,holdme)
end end
function multi:newSystemThread(name, func, ...) function multi:newSystemThread(name, func, ...)
print("Creating a thread")
multi.InitSystemThreadErrorHandler() multi.InitSystemThreadErrorHandler()
local rand = math.random(1, 10000000) local rand = math.random(1, 10000000)
local return_linda = lanes.linda() local return_linda = lanes.linda()
@ -106,6 +102,7 @@ function multi:newSystemThread(name, func, ...)
return c return c
end end
function multi.InitSystemThreadErrorHandler() function multi.InitSystemThreadErrorHandler()
print("Thread Created!")
if started == true then if started == true then
return return
end end
@ -113,7 +110,11 @@ function multi.InitSystemThreadErrorHandler()
multi:newThread("SystemThreadScheduler",function() multi:newThread("SystemThreadScheduler",function()
local threads = multi.SystemThreads local threads = multi.SystemThreads
while true do while true do
thread.sleep(.01) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough. thread.sleep(.005) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
local _,data = __ConsoleLinda:receive(0, "Q")
if data then
print(unpack(data))
end
for i = #threads, 1, -1 do for i = #threads, 1, -1 do
local status = threads[i].thread.status local status = threads[i].thread.status
local temp = threads[i] local temp = threads[i]
@ -153,6 +154,7 @@ function multi.InitSystemThreadErrorHandler()
print(...) print(...)
end) end)
end end
multi.print("Integrated Lanes!") multi.print("Integrated Lanes!")
multi.integration = {} -- for module creators multi.integration = {} -- for module creators
multi.integration.GLOBAL = GLOBAL multi.integration.GLOBAL = GLOBAL

View File

@ -1,19 +1,28 @@
package.path = "./?/init.lua;"..package.path package.path = "./?/init.lua;"..package.path
local multi,thread = require("multi"):init() local multi,thread = require("multi"):init()
local GLOBAL,THREAD = require("multi.integration.threading"):init() local GLOBAL,THREAD = require("multi.integration.lanesManager"):init()
function sleep(n) -- func = THREAD:newFunction(function(a,b,c)
if n > 0 then os.execute("ping -n " .. tonumber(n+1) .. " localhost > NUL") end -- print("Hello Thread!",a,b,c)
end -- return 1,2,3
-- end)
func = THREAD:newFunction(function(a,b,c) -- func2 = THREAD:newFunction(function(a,b,c)
print("Hello Thread!",a,b,c) -- print("Hello Thread2!",a,b,c)
return 1,2,3 -- THREAD.sleep(1)
-- return 10,11,12
-- end)
-- multi:newThread("Test thread",function()
-- handler = func(4,5,6)
-- handler2 = func2(7,8,9)
-- thread.hold(handler.OnReturn + handler2.OnReturn)
-- print("Function Done",handler.getReturns())
-- print("Function Done",handler2.getReturns())
-- end)
multi:benchMark(1):OnBench(function(sec,steps)
print("Steps:",steps)
os.exit()
end) end)
multi:newThread("Test thread",function()
handler = func(4,5,6)
thread.hold(handler.OnReturn)
print("Function Done",handler.getReturns())
end)
multi:mainloop() multi:mainloop()