1.9.2 is out!
Added, updated, and fixed stuff
This commit is contained in:
parent
509086295c
commit
e32720b687
19
PManager.txt
Normal file
19
PManager.txt
Normal file
@ -0,0 +1,19 @@
|
||||
C: 2731526 ~I*7
|
||||
H: 2341308 ~I*6
|
||||
A: 1951090 ~I*5
|
||||
N: 1560872 ~I*4
|
||||
B: 1170655 ~I*3
|
||||
L: 780438 ~I*2
|
||||
I: 390219 ~I
|
||||
~n=I*PRank
|
||||
|
||||
P2
|
||||
---------------
|
||||
C: 6700821
|
||||
H: 1675205
|
||||
A: 418801
|
||||
N: 104700
|
||||
B: 26175
|
||||
L: 6543
|
||||
I: 1635
|
||||
~n=n*4
|
||||
80
README.html
80
README.html
File diff suppressed because one or more lines are too long
54
README.md
54
README.md
@ -1,9 +1,7 @@
|
||||
# multi Version: 1.9.1 (New Integration! luvit)
|
||||
# multi Version: 1.9.2 (Yes I am alive, and some tweaks and additions have been made)
|
||||
|
||||
**NOTE: I have been studying a lot about threading in the past few weeks and have some awesome additions in store! They will take a while to come out though. The goal of the library is still to provide a simple and efficient way to multi task in lua**
|
||||
|
||||
**Upcoming Plans:** Adding network support for threading. Kinda like your own lua cloud. This will require the bin, net, and multi library. Once that happens I will include those libraries as a set. This also means that you can expect both a stand alone and joined versions of the libraries.
|
||||
|
||||
In Changes you'll find documentation for(In Order):
|
||||
- Sterilizing Objects
|
||||
- System Threaded Job Queues
|
||||
@ -35,6 +33,8 @@ Discord
|
||||
For real-time assistance with my libraries! A place where you can ask questions and get help with any of my libraries. Also you can request features and stuff there as well.</br>
|
||||
https://discord.gg/U8UspuA</br>
|
||||
|
||||
**Upcoming Plans:** Adding network support for threading. Kinda like your own lua cloud. This will require the bin, net, and multi library. Once that happens I will include those libraries as a set. This also means that you can expect both a stand alone and joined versions of the libraries.
|
||||
|
||||
Planned features/TODO
|
||||
---------------------
|
||||
- [x] ~~Add system threads for love2d that works like the lanesManager (loveManager, slight differences).~~
|
||||
@ -813,20 +813,48 @@ We did it! 1 2 3</br>
|
||||
|
||||
Changes
|
||||
-------
|
||||
Update: 1.9.1
|
||||
Update: 1.9.2
|
||||
-------------
|
||||
Added:
|
||||
Integration "multi.integration.luvitManager"
|
||||
Limited... Only the basic multi:newSystemThread(...) will work
|
||||
Not even data passing will work other than arguments... If using the bin library you can pass tables and function... Even full objects as long as inner recursion is not preasent.
|
||||
- (THREAD).kill() kills a thread. Note: THREAD is based on what you name it
|
||||
- newTimeStamper() Part of the persistant systems... Useful for when you are running this library for a massive amount of time... like years stright!
|
||||
Allows one to hook to timed events such as whenever the clock strikes midnight or when the day turns to monday. The event is only done once though. so as soon as monday is set it would trigger then not trigger again until next monday
|
||||
works for seconds, minutes, days, months, year.
|
||||
```lua
|
||||
stamper = multi:newTimeStamper()
|
||||
stamper:OnTime(int hour,int minute,int second,func) or stamper:OnTime(string time,func) time as 00:00:00
|
||||
stamper:OnHour(int hour,func)
|
||||
stamper:OnMinute(int minute,func)
|
||||
stamper:OnSecond(int second,func)
|
||||
stamper:OnDay(int day,func) or stamper:OnDay(string day,func) Mon, Tues, Wed, etc...
|
||||
stamper:OnMonth(int month,func)
|
||||
stamper:OnYear(int year,func)
|
||||
```
|
||||
Updated:
|
||||
- LoadBalancing, well bettwr load balancing than existed before. This one allowd for multiple processes to have their own load reading. Calling this on the multi object will return the total load for the entire multi enviroment... loads of other processes are indeed affected by what other processes are doing. However if you combine prorioty to the mix of things then you will get differing results... these results however will most likely be higher than normal... different pirorities will have different default thresholds of performence.
|
||||
|
||||
Fixed:
|
||||
- Thread.getName() should now work on lanes and love2d, haven't tested ut nuch with the luvit side of things...
|
||||
- A bug with the lovemanager table.remove arguments were backwards haha
|
||||
- The queue object in the love2d threading has been fixed! It now supports sending all objects (even functions as long as no upvalues are present!)
|
||||
|
||||
Changed:
|
||||
- SystemThreadedJobQueues now have built in load management so they are not constantly at 100% cpu usage.
|
||||
- SystemThreadedJobQueues pushJob now retunts an id of that job which will match the same one that OnJobCompleted returns
|
||||
|
||||
|
||||
Update: 1.9.1
|
||||
-------------
|
||||
Added:
|
||||
- Integration "multi.integration.luvitManager"
|
||||
- Limited... Only the basic multi:newSystemThread(...) will work
|
||||
- Not even data passing will work other than arguments... If using the bin library you can pass tables and function... Even full objects as long as inner recursion is not preasent.
|
||||
|
||||
Updated:
|
||||
multi:newSystemThread(name,func,...)
|
||||
- multi:newSystemThread(name,func,...)
|
||||
- It will not pass the ... to the func(). Do not know why this wasn't done in the first place :P
|
||||
- Also multi:getPlatform(will now return "luvit" if using luvit... Though Idk if module creators would use the multi library when inside the luvit enviroment
|
||||
|
||||
It will not pass the ... to the func()
|
||||
|
||||
Do not know why this wasn't done in the first place :P
|
||||
|
||||
Also multi:getPlatform(will now return "luvit" if using luvit... Though Idk if module creators would use the multi library when inside the luvit enviroment
|
||||
Update: 1.9.0
|
||||
-------------
|
||||
Added:
|
||||
|
||||
@ -32,7 +32,7 @@ multi:newThread("test0",function()
|
||||
end
|
||||
end
|
||||
end)
|
||||
GLOBAL["BENCH"]=10
|
||||
GLOBAL["BENCH"]=1
|
||||
print("Platform is: ",multi:getPlatform()) -- returns love2d or lanes depending on which platform you are using... If I add more intergrations then this method will be updated! corona sdk may see this library in the future...
|
||||
multi:mainloop()
|
||||
--[[ Output on my machine! I am using luajit and have 6 cores on my computer. Your numbers will vary, but it should look something like this
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package.path="?/init.lua;"..package.path
|
||||
--~ package.path="?/init.lua;"..package.path
|
||||
local GLOBAL,sThread=require("multi.integration.lanesManager").init()
|
||||
jQueue=multi:newSystemThreadedJobQueue(n)
|
||||
jQueue:registerJob("TEST_JOB",function(a,s)
|
||||
@ -11,7 +11,7 @@ jQueue:registerJob("TEST_JOB2",function()
|
||||
end)
|
||||
jQueue:start()
|
||||
jQueue:doToAll(function()
|
||||
print("Doing this 6? times!")
|
||||
print("Doing this 16? times!")
|
||||
end)
|
||||
for i=1,10 do -- Job Name of registered function, ... varargs
|
||||
jQueue:pushJob("TEST_JOB","This is a test!",math.random(1,1000000))
|
||||
|
||||
388
multi/init.lua
388
multi/init.lua
@ -22,6 +22,62 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
require("bin")
|
||||
multi = {}
|
||||
multi.Version = "1.9.2"
|
||||
multi._VERSION = "1.9.2"
|
||||
multi.stage = "mostly-stable"
|
||||
multi.__index = multi
|
||||
multi.Mainloop = {}
|
||||
multi.Tasks = {}
|
||||
multi.Tasks2 = {}
|
||||
multi.Garbage = {}
|
||||
multi.ender = {}
|
||||
multi.Children = {}
|
||||
multi.Paused = {}
|
||||
multi.Active = true
|
||||
multi.fps = 60
|
||||
multi.Id = -1
|
||||
multi.Type = "mainprocess"
|
||||
multi.Rest = 0
|
||||
multi._type = type
|
||||
multi.Jobs = {}
|
||||
multi.queue = {}
|
||||
multi.jobUS = 2
|
||||
multi.clock = os.clock
|
||||
multi.time = os.time
|
||||
multi.LinkedPath = multi
|
||||
multi.isRunning = false
|
||||
--Do not change these ever...Any other number will not work (Unless you are using enablePriority2())
|
||||
multi.Priority_Core = 1
|
||||
multi.Priority_High = 4
|
||||
multi.Priority_Above_Normal = 16
|
||||
multi.Priority_Normal = 64
|
||||
multi.Priority_Below_Normal = 256
|
||||
multi.Priority_Low = 1024
|
||||
multi.Priority_Idle = 4096
|
||||
multi.PStep = 1
|
||||
multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
|
||||
--^^^^
|
||||
multi.PriorityTick=1 -- Between 1, 2 and 4
|
||||
multi.Priority=multi.Priority_Core
|
||||
multi.threshold=256
|
||||
multi.threstimed=.001
|
||||
function multi.queuefinal(self)
|
||||
self:Destroy()
|
||||
if self.Parent.Mainloop[#self.Parent.Mainloop] then
|
||||
if self.Parent.Mainloop[#self.Parent.Mainloop].Type=="alarm" then
|
||||
self.Parent.Mainloop[#self.Parent.Mainloop]:Reset()
|
||||
self.Parent.Mainloop[#self.Parent.Mainloop].Active=true
|
||||
else
|
||||
self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
|
||||
end
|
||||
else
|
||||
for i=1,#self.Parent.funcE do
|
||||
self.Parent.funcE[i](self)
|
||||
end
|
||||
self.Parent:Remove()
|
||||
end
|
||||
end
|
||||
if table.unpack then
|
||||
unpack=table.unpack
|
||||
end
|
||||
@ -45,83 +101,19 @@ function print(...)
|
||||
_print(...)
|
||||
end
|
||||
end
|
||||
multi = {}
|
||||
multi.Version="1.9.1"
|
||||
multi._VERSION="1.9.1"
|
||||
multi.stage='mostly-stable'
|
||||
multi.__index = multi
|
||||
multi.Mainloop={}
|
||||
multi.Tasks={}
|
||||
multi.Tasks2={}
|
||||
multi.Garbage={}
|
||||
multi.ender={}
|
||||
multi.Children={}
|
||||
multi.Paused={}
|
||||
multi.Active=true
|
||||
multi.fps=60
|
||||
multi.Id=-1
|
||||
multi.Type='mainprocess'
|
||||
multi.Rest=0
|
||||
multi._type=type
|
||||
multi.Jobs={}
|
||||
multi.queue={}
|
||||
multi.jobUS=2
|
||||
multi.clock=os.clock
|
||||
multi.time=os.time
|
||||
multi.LinkedPath=multi
|
||||
multi.isRunning=false
|
||||
multi.queuefinal=function(self)
|
||||
self:Destroy()
|
||||
if self.Parent.Mainloop[#self.Parent.Mainloop] then
|
||||
if self.Parent.Mainloop[#self.Parent.Mainloop].Type=="alarm" then
|
||||
self.Parent.Mainloop[#self.Parent.Mainloop]:Reset()
|
||||
self.Parent.Mainloop[#self.Parent.Mainloop].Active=true
|
||||
else
|
||||
self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
|
||||
end
|
||||
else
|
||||
for i=1,#self.Parent.funcE do
|
||||
self.Parent.funcE[i](self)
|
||||
end
|
||||
self.Parent:Remove()
|
||||
_write=io.write
|
||||
function io.write(...)
|
||||
if not __SUPPRESSWRITES then
|
||||
_write(...)
|
||||
end
|
||||
end
|
||||
--Do not change these ever...Any other number will not work (Unless you are using enablePriority2())
|
||||
multi.Priority_Core=1
|
||||
multi.Priority_High=4
|
||||
multi.Priority_Above_Normal=16
|
||||
multi.Priority_Normal=64
|
||||
multi.Priority_Below_Normal=256
|
||||
multi.Priority_Low=1024
|
||||
multi.Priority_Idle=4096
|
||||
multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
|
||||
multi.PStep=1
|
||||
--^^^^
|
||||
multi.PriorityTick=1 -- Between 1,2 and 4
|
||||
multi.Priority=multi.Priority_Core
|
||||
multi.threshold=256
|
||||
multi.threstimed=.001
|
||||
function multi:setThreshold(n)
|
||||
self.threshold=n or 120
|
||||
end
|
||||
function multi:setThrestimed(n)
|
||||
self.threstimed=n or .001
|
||||
self.deltaTarget=n or .1
|
||||
end
|
||||
function multi:getLoad()
|
||||
return multi:newFunction(function(self)
|
||||
multi.scheduler:Pause()
|
||||
local sample=#multi.Mainloop
|
||||
local FFloadtest=0
|
||||
multi:benchMark(multi.threstimed):OnBench(function(_,l3) FFloadtest=l3*(1/multi.threstimed) end)
|
||||
self:hold(function() return FFloadtest~=0 end)
|
||||
local val=FFloadtest/sample
|
||||
multi.scheduler:Resume()
|
||||
if val>multi.threshold then
|
||||
return 0
|
||||
else
|
||||
return 100-((val/multi.threshold)*100)
|
||||
end
|
||||
end)()
|
||||
if multi.load_updater:isPaused() then multi.load_updater:Resume() return 0 end
|
||||
local val = math.abs(self.dStepA-self.dStepB)/multi.deltaTarget*100
|
||||
if val > 100 then return 100 else return val end
|
||||
end
|
||||
function multi:setDomainName(name)
|
||||
self[name]={}
|
||||
@ -195,6 +187,7 @@ multi.Condition=multi.condition
|
||||
function multi:isHeld()
|
||||
return self.held
|
||||
end
|
||||
multi.important={}
|
||||
multi.IsHeld=multi.isHeld
|
||||
function multi.executeFunction(name,...)
|
||||
if type(_G[name])=='function' then
|
||||
@ -214,14 +207,39 @@ end
|
||||
multi.WaitFor=multi.waitFor
|
||||
function multi:reboot(r)
|
||||
local before=collectgarbage('count')
|
||||
self.Mainloop={}
|
||||
self.Tasks={}
|
||||
self.Tasks2={}
|
||||
self.Garbage={}
|
||||
self.Children={}
|
||||
self.Paused={}
|
||||
self.Active=true
|
||||
self.Id=-1
|
||||
multi.Mainloop={}
|
||||
multi.Tasks={}
|
||||
multi.Tasks2={}
|
||||
multi.Garbage={}
|
||||
multi.ender={}
|
||||
multi.Children={}
|
||||
multi.Paused={}
|
||||
multi.Active=true
|
||||
multi.fps=60
|
||||
multi.Id=-1
|
||||
multi.Type='mainprocess'
|
||||
multi.Rest=0
|
||||
multi._type=type
|
||||
multi.Jobs={}
|
||||
multi.queue={}
|
||||
multi.jobUS=2
|
||||
multi.clock=os.clock
|
||||
multi.time=os.time
|
||||
multi.LinkedPath=multi
|
||||
multi.isRunning=false
|
||||
multi.Priority_Core=1
|
||||
multi.Priority_High=4
|
||||
multi.Priority_Above_Normal=16
|
||||
multi.Priority_Normal=64
|
||||
multi.Priority_Below_Normal=256
|
||||
multi.Priority_Low=1024
|
||||
multi.Priority_Idle=4096
|
||||
multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
|
||||
multi.PStep=1
|
||||
multi.PriorityTick=1
|
||||
multi.Priority=multi.Priority_Core
|
||||
multi.threshold=256
|
||||
multi.threstimed=.001
|
||||
if r then
|
||||
for i,v in pairs(_G) do
|
||||
if type(i)=='table' then
|
||||
@ -280,20 +298,18 @@ function multi:enablePriority()
|
||||
_G.ID=0
|
||||
local PS=self
|
||||
for _D=#Loop,1,-1 do
|
||||
if Loop[_D] then
|
||||
if (PS.PList[PS.PStep])%Loop[_D].Priority==0 then
|
||||
if Loop[_D].Active then
|
||||
Loop[_D].Id=_D
|
||||
self.CID=_D
|
||||
Loop[_D]:Act()
|
||||
for P=1,7 do
|
||||
if Loop[_D] then
|
||||
if (PS.PList[P])%Loop[_D].Priority==0 then
|
||||
if Loop[_D].Active then
|
||||
Loop[_D].Id=_D
|
||||
self.CID=_D
|
||||
Loop[_D]:Act()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
PS.PStep=PS.PStep+1
|
||||
if PS.PStep>7 then
|
||||
PS.PStep=1
|
||||
end
|
||||
end
|
||||
end
|
||||
function multi:enablePriority2()
|
||||
@ -701,6 +717,7 @@ function multi:newProcess(file)
|
||||
loadstring('local process=multi.Cself '..io.open(file,'rb'):read('*all'))()
|
||||
end
|
||||
self:create(c)
|
||||
--~ c:IngoreObject()
|
||||
return c
|
||||
end
|
||||
function multi:newQueuer(file)
|
||||
@ -772,7 +789,8 @@ function multi:newTimer()
|
||||
end
|
||||
function multi:newConnection(protect)
|
||||
local c={}
|
||||
setmetatable(c,{__call=function(self,...) self:connect(...) end})
|
||||
c.Parent=self
|
||||
setmetatable(c,{__call=function(self,...) return self:connect(...) end})
|
||||
c.Type='connector'
|
||||
c.func={}
|
||||
c.ID=0
|
||||
@ -780,6 +798,16 @@ function multi:newConnection(protect)
|
||||
c.connections={}
|
||||
c.fconnections={}
|
||||
c.FC=0
|
||||
function c:holdUT()
|
||||
self.waiting=true
|
||||
local id=self:connect(function()
|
||||
self.waiting=false
|
||||
end)
|
||||
repeat
|
||||
self.Parent:uManager()
|
||||
until self.waiting==false
|
||||
id:Destroy()
|
||||
end
|
||||
function c:fConnect(func)
|
||||
local temp=self:connect(func)
|
||||
table.insert(self.fconnections,temp)
|
||||
@ -852,8 +880,9 @@ function multi:newConnection(protect)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
temp.Destroy=temp.Remove
|
||||
if name then
|
||||
self.connections[name]=temp
|
||||
end
|
||||
@ -1123,7 +1152,7 @@ function multi:newUpdater(skip)
|
||||
end
|
||||
self.pos=self.pos+1
|
||||
end
|
||||
function c:setSkip(n)
|
||||
function c:SetSkip(n)
|
||||
self.skip=n
|
||||
end
|
||||
c.OnUpdate=self.OnMainConnect
|
||||
@ -1376,6 +1405,112 @@ function multi:newTStep(start,reset,count,set)
|
||||
self:create(c)
|
||||
return c
|
||||
end
|
||||
function multi:newTimeStamper()
|
||||
local c=self:newBase()
|
||||
c.Type='timestamper'
|
||||
c.Priority=self.Priority_Idle
|
||||
c.hour = {}
|
||||
c.minute = {}
|
||||
c.second = {}
|
||||
c.time = {}
|
||||
c.day = {}
|
||||
c.month = {}
|
||||
c.year = {}
|
||||
function c:Act()
|
||||
for i=1,#self.hour do
|
||||
if self.hour[i][1]==os.date("%H") and self.hour[i][3] then
|
||||
self.hour[i][2](self)
|
||||
self.hour[i][3]=false
|
||||
elseif self.hour[i][1]~=os.date("%H") and not self.hour[i][3] then
|
||||
self.hour[i][3]=true
|
||||
end
|
||||
end
|
||||
for i=1,#self.minute do
|
||||
if self.minute[i][1]==os.date("%M") and self.minute[i][3] then
|
||||
self.minute[i][2](self)
|
||||
self.minute[i][3]=false
|
||||
elseif self.minute[i][1]~=os.date("%M") and not self.minute[i][3] then
|
||||
self.minute[i][3]=true
|
||||
end
|
||||
end
|
||||
for i=1,#self.second do
|
||||
if self.second[i][1]==os.date("%S") and self.second[i][3] then
|
||||
self.second[i][2](self)
|
||||
self.second[i][3]=false
|
||||
elseif self.second[i][1]~=os.date("%S") and not self.second[i][3] then
|
||||
self.second[i][3]=true
|
||||
end
|
||||
end
|
||||
for i=1,#self.day do
|
||||
if type(self.day[i][1])=="string" then
|
||||
if self.day[i][1]==os.date("%a") and self.day[i][3] then
|
||||
self.day[i][2](self)
|
||||
self.day[i][3]=false
|
||||
elseif self.day[i][1]~=os.date("%a") and not self.day[i][3] then
|
||||
self.day[i][3]=true
|
||||
end
|
||||
else
|
||||
if string.format("%02d",self.day[i][1])==os.date("%d") and self.day[i][3] then
|
||||
self.day[i][2](self)
|
||||
self.day[i][3]=false
|
||||
elseif string.format("%02d",self.day[i][1])~=os.date("%d") and not self.day[i][3] then
|
||||
self.day[i][3]=true
|
||||
end
|
||||
end
|
||||
end
|
||||
for i=1,#self.month do
|
||||
if self.month[i][1]==os.date("%m") and self.month[i][3] then
|
||||
self.month[i][2](self)
|
||||
self.month[i][3]=false
|
||||
elseif self.month[i][1]~=os.date("%m") and not self.month[i][3] then
|
||||
self.month[i][3]=true
|
||||
end
|
||||
end
|
||||
for i=1,#self.time do
|
||||
if self.time[i][1]==os.date("%X") and self.time[i][3] then
|
||||
self.time[i][2](self)
|
||||
self.time[i][3]=false
|
||||
elseif self.time[i][1]~=os.date("%X") and not self.time[i][3] then
|
||||
self.time[i][3]=true
|
||||
end
|
||||
end
|
||||
for i=1,#self.year do
|
||||
if self.year[i][1]==os.date("%y") and self.year[i][3] then
|
||||
self.year[i][2](self)
|
||||
self.year[i][3]=false
|
||||
elseif self.year[i][1]~=os.date("%y") and not self.year[i][3] then
|
||||
self.year[i][3]=true
|
||||
end
|
||||
end
|
||||
end
|
||||
function c:OnTime(hour,minute,second,func)
|
||||
if type(hour)=="number" then
|
||||
self.time[#self.time+1]={string.format("%02d:%02d:%02d",hour,minute,second),func,true}
|
||||
else
|
||||
self.time[#self.time+1]={hour,minute,true}
|
||||
end
|
||||
end
|
||||
function c:OnHour(hour,func)
|
||||
self.hour[#self.hour+1]={string.format("%02d",hour),func,true}
|
||||
end
|
||||
function c:OnMinute(minute,func)
|
||||
self.minute[#self.minute+1]={string.format("%02d",minute),func,true}
|
||||
end
|
||||
function c:OnSecond(second,func)
|
||||
self.second[#self.second+1]={string.format("%02d",second),func,true}
|
||||
end
|
||||
function c:OnDay(day,func)
|
||||
self.day[#self.day+1]={day,func,true}
|
||||
end
|
||||
function c:OnMonth(month,func)
|
||||
self.month[#self.month+1]={string.format("%02d",month),func,true}
|
||||
end
|
||||
function c:OnYear(year,func)
|
||||
self.year[#self.year+1]={string.format("%02d",year),func,true}
|
||||
end
|
||||
self:create(c)
|
||||
return c
|
||||
end
|
||||
function multi:newWatcher(namespace,name)
|
||||
local function WatcherObj(ns,n)
|
||||
if self.Type=='queue' then
|
||||
@ -1462,6 +1597,7 @@ function multi:newTBase(name)
|
||||
c.important={}
|
||||
c.held=false
|
||||
c.ToString=multi.ToString
|
||||
c.ToFile=multi.ToFile
|
||||
return c
|
||||
end
|
||||
function multi:newThread(name,func)
|
||||
@ -1992,9 +2128,15 @@ function multi:newThreadedEvent(name,task)
|
||||
return c
|
||||
end
|
||||
-- State Saving Stuff
|
||||
function multi:IngoreObject()
|
||||
self.Ingore=true
|
||||
end
|
||||
multi.scheduler:IngoreObject()
|
||||
function multi:ToString()
|
||||
if self.Ingore then return end
|
||||
local t=self.Type
|
||||
local data;
|
||||
print(t)
|
||||
if t:sub(-6)=="Thread" then
|
||||
data={
|
||||
Type=t,
|
||||
@ -2025,9 +2167,7 @@ function multi:ToString()
|
||||
held=self.held,
|
||||
}
|
||||
end
|
||||
if t=="process" then
|
||||
--
|
||||
elseif t=="eventThread" or t=="event" then
|
||||
if t=="eventThread" or t=="event" then
|
||||
table.merge(data,{
|
||||
Task=self.Task,
|
||||
})
|
||||
@ -2095,6 +2235,23 @@ function multi:ToString()
|
||||
set=self.set,
|
||||
link=self.link,
|
||||
})
|
||||
elseif t=="process" or t=="mainprocess" then
|
||||
local loop=self.Mainloop
|
||||
local dat={}
|
||||
for i=1,#loop do
|
||||
local ins=loop[i]:ToString()
|
||||
if ins~=nil then
|
||||
table.insert(dat,ins)
|
||||
end
|
||||
end
|
||||
local str=bin.new()
|
||||
str:addBlock({Type=t})
|
||||
str:addBlock(#dat,4,"n")
|
||||
for i=1,#dat do
|
||||
str:addBlock(#dat[i],4,"n")
|
||||
str:addBlock(dat[i])
|
||||
end
|
||||
return str.data
|
||||
end
|
||||
for i,v in pairs(self.important) do
|
||||
data[v]=self[v]
|
||||
@ -2109,9 +2266,23 @@ function multi:newFromString(str)
|
||||
str=str.data
|
||||
end
|
||||
end
|
||||
local data=bin.new(str):getBlock("t")
|
||||
local handle=bin.new(str)
|
||||
local data=handle:getBlock("t")
|
||||
local t=data.Type
|
||||
if t=="step" then -- GOOD
|
||||
if t=="mainprocess" then
|
||||
local objs=handle:getBlock("n",4)
|
||||
for i=1,objs do
|
||||
self:newFromString(handle:getBlock("s",(handle:getBlock("n",4))))
|
||||
end
|
||||
return self
|
||||
elseif t=="process" then
|
||||
local temp=multi:newProcess()
|
||||
local objs=handle:getBlock("n",4)
|
||||
for i=1,objs do
|
||||
temp:newFromString(handle:getBlock("s",(handle:getBlock("n",4))))
|
||||
end
|
||||
return temp
|
||||
elseif t=="step" then -- GOOD
|
||||
local item=self:newStep()
|
||||
table.merge(item,data)
|
||||
return item
|
||||
@ -2176,6 +2347,12 @@ end
|
||||
function multi:Important(varname)
|
||||
table.insert(important,varname)
|
||||
end
|
||||
function multi:ToFile(path)
|
||||
bin.new(self:ToString()):tofile(path)
|
||||
end
|
||||
function multi:fromFile(path)
|
||||
self:newFromString(bin.load(path))
|
||||
end
|
||||
function multi:SetStateFlag(opt)
|
||||
--
|
||||
end
|
||||
@ -2191,3 +2368,18 @@ end
|
||||
function multi:setDefualtStateFlag(opt)
|
||||
--
|
||||
end
|
||||
multi.dStepA = 0
|
||||
multi.dStepB = 0
|
||||
multi.dSwap = 0
|
||||
multi.deltaTarget = .05
|
||||
multi.load_updater = multi:newUpdater(2)
|
||||
multi.load_updater:Pause()
|
||||
multi.load_updater:OnUpdate(function(self)
|
||||
if self.Parent.dSwap == 0 then
|
||||
self.Parent.dStepA = os.clock()
|
||||
self.Parent.dSwap = 1
|
||||
else
|
||||
self.Parent.dSwap = 0
|
||||
self.Parent.dStepB = os.clock()
|
||||
end
|
||||
end)
|
||||
|
||||
@ -89,7 +89,10 @@ else
|
||||
THREAD.__CORES=tonumber(io.popen("nproc --all"):read("*n"))
|
||||
end
|
||||
function THREAD.kill() -- trigger the lane destruction
|
||||
-- coroutine.yield({"_kill_",":)"})
|
||||
error("Thread was killed!")
|
||||
end
|
||||
function THREAD.getName()
|
||||
return THREAD_NAME
|
||||
end
|
||||
--[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait
|
||||
Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method
|
||||
@ -111,7 +114,12 @@ function multi:newSystemThread(name,func,...)
|
||||
local __self=c
|
||||
c.name=name
|
||||
c.Type="sthread"
|
||||
c.thread=lanes.gen("*", func)(...)
|
||||
local THREAD_NAME=name
|
||||
local function func2(...)
|
||||
_G["THREAD_NAME"]=THREAD_NAME
|
||||
func()
|
||||
end
|
||||
c.thread=lanes.gen("*", func2)(...)
|
||||
function c:kill()
|
||||
--self.status:Destroy()
|
||||
self.thread:cancel()
|
||||
|
||||
@ -9,11 +9,12 @@ multi.integration={}
|
||||
multi.integration.love2d={}
|
||||
multi.integration.love2d.ThreadBase=[[
|
||||
tab={...}
|
||||
__THREADID__=table.remove(1,tab)
|
||||
__THREADNAME__=table.remove(1,tab)
|
||||
__THREADID__=table.remove(tab,1)
|
||||
__THREADNAME__=table.remove(tab,1)
|
||||
require("love.filesystem")
|
||||
require("love.system")
|
||||
require("love.timer")
|
||||
require("love.image")
|
||||
require("multi")
|
||||
GLOBAL={}
|
||||
setmetatable(GLOBAL,{
|
||||
@ -34,7 +35,7 @@ setmetatable(GLOBAL,{
|
||||
function __sync__()
|
||||
local data=__mythread__:pop()
|
||||
while data do
|
||||
love.timer.sleep(.001)
|
||||
love.timer.sleep(.01)
|
||||
if type(data)=="string" then
|
||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
||||
if name=="__DIEPLZ"..__THREADID__.."__" then
|
||||
@ -139,6 +140,12 @@ function dump(func)
|
||||
end
|
||||
return table.concat(code)
|
||||
end
|
||||
function sThread.getName()
|
||||
return __THREADNAME__
|
||||
end
|
||||
function sThread.kill()
|
||||
error("Thread was killed!")
|
||||
end
|
||||
function sThread.set(name,val)
|
||||
GLOBAL[name]=val
|
||||
end
|
||||
@ -158,14 +165,6 @@ end
|
||||
function sThread.hold(n)
|
||||
repeat __sync__() until n()
|
||||
end
|
||||
multi:newLoop(function(self)
|
||||
self:Pause()
|
||||
local ld=multi:getLoad()
|
||||
self:Resume()
|
||||
if ld<80 then
|
||||
love.timer.sleep(.01)
|
||||
end
|
||||
end)
|
||||
updater=multi:newUpdater()
|
||||
updater:OnUpdate(__sync__)
|
||||
func=loadDump([=[INSERT_USER_CODE]=])(unpack(tab))
|
||||
@ -190,6 +189,9 @@ setmetatable(GLOBAL,{
|
||||
})
|
||||
THREAD={} -- Allow main thread to interact with these objects as well
|
||||
multi.integration.love2d.mainChannel=love.thread.getChannel("__MainChan__")
|
||||
function THREAD.getName()
|
||||
return __THREADNAME__
|
||||
end
|
||||
function ToStr(val, name, skipnewlines, depth)
|
||||
skipnewlines = skipnewlines or false
|
||||
depth = depth or 0
|
||||
|
||||
@ -37,19 +37,62 @@ function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a chann
|
||||
function c:init() -- create an init function so we can mimic on bith love2d and lanes
|
||||
self.chan=love.thread.getChannel(self.name) -- create channel by the name self.name
|
||||
function self:push(v) -- push to the channel
|
||||
self.chan:push({type(v),resolveData(v)})
|
||||
local tab
|
||||
if type(v)=="table" then
|
||||
tab = {}
|
||||
for i,c in pairs(v) do
|
||||
if type(c)=="function" then
|
||||
tab[i]="\1"..string.dump(c)
|
||||
else
|
||||
tab[i]=c
|
||||
end
|
||||
end
|
||||
self.chan:push(tab)
|
||||
else
|
||||
self.chan:push(c)
|
||||
end
|
||||
end
|
||||
function self:pop() -- pop from the channel
|
||||
local tab=self.chan:pop()
|
||||
--print(tab)
|
||||
if not tab then return end
|
||||
return resolveType(tab[1],tab[2])
|
||||
local v=self.chan:pop()
|
||||
if not v then return end
|
||||
if type(v)=="table" then
|
||||
tab = {}
|
||||
for i,c in pairs(v) do
|
||||
if type(c)=="string" then
|
||||
if c:sub(1,1)=="\1" then
|
||||
tab[i]=loadstring(c:sub(2,-1))
|
||||
else
|
||||
tab[i]=c
|
||||
end
|
||||
else
|
||||
tab[i]=c
|
||||
end
|
||||
end
|
||||
return tab
|
||||
else
|
||||
return self.chan:pop()
|
||||
end
|
||||
end
|
||||
function self:peek()
|
||||
local tab=self.chan:peek()
|
||||
--print(tab)
|
||||
if not tab then return end
|
||||
return resolveType(tab[1],tab[2])
|
||||
local v=self.chan:peek()
|
||||
if not v then return end
|
||||
if type(v)=="table" then
|
||||
tab = {}
|
||||
for i,c in pairs(v) do
|
||||
if type(c)=="string" then
|
||||
if c:sub(1,1)=="\1" then
|
||||
tab[i]=loadstring(c:sub(2,-1))
|
||||
else
|
||||
tab[i]=c
|
||||
end
|
||||
else
|
||||
tab[i]=c
|
||||
end
|
||||
end
|
||||
return tab
|
||||
else
|
||||
return self.chan:pop()
|
||||
end
|
||||
end
|
||||
GLOBAL[self.name]=self -- send the object to the thread through the global interface
|
||||
return self -- return the object
|
||||
@ -120,7 +163,7 @@ function multi:systemThreadedBenchmark(n,p)
|
||||
end)
|
||||
return c
|
||||
end
|
||||
function multi:newSystemThreadedTable(name,n)
|
||||
function multi:newSystemThreadedTable(name,n) -- NEDS FIXING SING SO MUCH WORK!!!
|
||||
local c={} -- where we will store our object
|
||||
c.name=name -- set the name this is important for the love2d side
|
||||
c.cores=n
|
||||
@ -212,8 +255,7 @@ function multi:newSystemThreadedJobQueue(numOfCores)
|
||||
c.queueOUT=multi:newSystemThreadedQueue("THREADED_JQO"):init()
|
||||
c.queueALL=multi:newSystemThreadedQueue("THREADED_QALL"):init()
|
||||
c.REG=multi:newSystemThreadedQueue("THREADED_JQ_F_REG"):init()
|
||||
-- registerJob(name,func)
|
||||
-- pushJob(...)
|
||||
c.OnReady=multi:newConnection()
|
||||
function c:registerJob(name,func)
|
||||
for i=1,self.cores do
|
||||
self.REG:push({name,func})
|
||||
@ -222,6 +264,7 @@ function multi:newSystemThreadedJobQueue(numOfCores)
|
||||
function c:pushJob(name,...)
|
||||
self.queueOUT:push({self.jobnum,name,...})
|
||||
self.jobnum=self.jobnum+1
|
||||
return self.jobnum-1
|
||||
end
|
||||
local GLOBAL=multi.integration.GLOBAL -- set up locals incase we are using lanes
|
||||
local sThread=multi.integration.THREAD -- set up locals incase we are using lanes
|
||||
@ -232,15 +275,24 @@ function multi:newSystemThreadedJobQueue(numOfCores)
|
||||
end
|
||||
end
|
||||
function c:start()
|
||||
self:doToAll(function()
|
||||
_G["__started__"]=true
|
||||
SFunc()
|
||||
multi:newEvent(function()
|
||||
return self.ThreadsLoaded==true
|
||||
end):OnEvent(function(evnt)
|
||||
GLOBAL["THREADED_JQ"]=nil -- remove it
|
||||
GLOBAL["THREADED_JQO"]=nil -- remove it
|
||||
GLOBAL["THREADED_JQ_F_REG"]=nil -- remove it
|
||||
self:doToAll(function()
|
||||
_G["__started__"]=true
|
||||
SFunc()
|
||||
end)
|
||||
evnt:Destroy()
|
||||
end)
|
||||
end
|
||||
GLOBAL["__JQ_COUNT__"]=c.cores
|
||||
for i=1,c.cores do
|
||||
multi:newSystemThread("System Threaded Job Queue Worker Thread #"..i,function()
|
||||
multi:newSystemThread("System Threaded Job Queue Worker Thread #"..i,function(name,ind)
|
||||
require("multi")
|
||||
ThreadName=name
|
||||
__sleep__=.001
|
||||
if love then -- lets make sure we don't reference upvalues if using love2d
|
||||
GLOBAL=_G.GLOBAL
|
||||
@ -251,10 +303,6 @@ function multi:newSystemThreadedJobQueue(numOfCores)
|
||||
JQO=sThread.waitFor("THREADED_JQ"):init() -- Grab it
|
||||
REG=sThread.waitFor("THREADED_JQ_F_REG"):init() -- Grab it
|
||||
QALL=sThread.waitFor("THREADED_QALL"):init() -- Grab it
|
||||
sThread.sleep(.1) -- lets wait for things to work out
|
||||
GLOBAL["THREADED_JQ"]=nil -- remove it
|
||||
GLOBAL["THREADED_JQO"]=nil -- remove it
|
||||
GLOBAL["THREADED_JQ_F_REG"]=nil -- remove it
|
||||
QALLT={}
|
||||
FUNCS={}
|
||||
SFunc=multi:newFunction(function(self)
|
||||
@ -287,10 +335,12 @@ function multi:newSystemThreadedJobQueue(numOfCores)
|
||||
return FUNCS[k]
|
||||
end
|
||||
})
|
||||
lastjob=os.clock()
|
||||
MainLoop=multi:newLoop(function(self)
|
||||
if __started__ then
|
||||
local job=JQI:pop()
|
||||
if job then
|
||||
lastjob=os.clock()
|
||||
local d=QALL:peek()
|
||||
if d then
|
||||
if not QALLT[d[1]] then
|
||||
@ -311,17 +361,34 @@ function multi:newSystemThreadedJobQueue(numOfCores)
|
||||
end
|
||||
end
|
||||
end)
|
||||
multi:newThread("Idler",function()
|
||||
while true do
|
||||
if os.clock()-lastjob>1 then
|
||||
sThread.sleep(.1)
|
||||
end
|
||||
thread.sleep(.001)
|
||||
end
|
||||
end)
|
||||
JQO:push({"_THREADINIT_",ind})
|
||||
if not love then
|
||||
multi:mainloop()
|
||||
end
|
||||
end)
|
||||
end,"Thread<"..i..">",i)
|
||||
end
|
||||
c.OnJobCompleted=multi:newConnection()
|
||||
c.updater=multi:newLoop(function(self)
|
||||
local data=self.link.queueIN:pop()
|
||||
while data do
|
||||
if data then
|
||||
self.link.OnJobCompleted:Fire(unpack(data))
|
||||
local a,b=unpack(data)
|
||||
if a=="_THREADINIT_" then
|
||||
if b==self.link.cores then
|
||||
self.link.ThreadsLoaded=true
|
||||
self.link.OnReady:Fire()
|
||||
end
|
||||
else
|
||||
self.link.OnJobCompleted:Fire(unpack(data))
|
||||
end
|
||||
end
|
||||
data=self.link.queueIN:pop()
|
||||
end
|
||||
|
||||
33
rockspecs/multi-1.9-2.rockspec
Normal file
33
rockspecs/multi-1.9-2.rockspec
Normal file
@ -0,0 +1,33 @@
|
||||
package = "multi"
|
||||
version = "1.9-2"
|
||||
source = {
|
||||
url = "git://github.com/rayaman/multi.git",
|
||||
tag = "v1.9.1",
|
||||
}
|
||||
description = {
|
||||
summary = "Lua Multi tasking library",
|
||||
detailed = [[
|
||||
This library contains many methods for multi tasking. From simple side by side code using multiobjs, to using coroutine based Threads and System threads(When you have lua lanes installed or are using love2d. Optional) The core of the library works on lua 5.1+ however the systemthreading features are limited to 5.1 due to love2d and lua lanes and now luvit (See ReadMe on gotchas) being lua 5.1 only!
|
||||
]],
|
||||
homepage = "https://github.com/rayaman/multi",
|
||||
license = "MIT"
|
||||
}
|
||||
dependencies = {
|
||||
"lua >= 5.1",
|
||||
"bin",
|
||||
"lanes"
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
-- Note the required Lua syntax when listing submodules as keys
|
||||
["multi.init"] = "multi/init.lua",
|
||||
["multi.all"] = "multi/all.lua",
|
||||
["multi.compat.backwards[1,5,0]"] = "multi/compat/backwards[1,5,0].lua",
|
||||
["multi.compat.love2d"] = "multi/compat/love2d.lua",
|
||||
["multi.integration.lanesManager"] = "multi/integration/lanesManager.lua",
|
||||
["multi.integration.loveManager"] = "multi/integration/loveManager.lua",
|
||||
["multi.integration.luvitManager"] = "multi/integration/luvitManager.lua",
|
||||
["multi.integration.shared"] = "multi/integration/shared.lua"
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user