Dead simple threads example
Posted: Tue Sep 06, 2016 1:34 pm
--------------------------------------------------------------
EDIT:
If you are looking for the threads example, i am putting that in this section so you dont have to go through other questions and discussions.
Here is my default code.
if you run it, you can see how the window is unresponsive for a few seconds while the logic loop runs. (if you have a non potato PC, you may increase the for loop range so the effect is more prominent)
Now the same code using threads. the main file is now broekn into 2 files: main.lua and backend.lua.
main calls backend as a thread and the backend keeps the main appraised of the current for loop progress via a channel.
main.lua
and backend.lua
Finally, we run the same code using coroutines
some basic takeaway:
threads is just as fast as normal blocking operation. However, it feels like threads are meant for long running operations like physics. creating a new thread for every short lived operation may not be ideal. i still need to research this more.
coroutines is definitely slower. the lag becomes more apparent when you increase the for loop range (for small ranges the lag is negligible).
Anyway, if i find any more ways of doing non blocking code (I might try async and some other parallel/concurrent programming libs next) i'll update my thread.
--------------------------------------------------------------
hi
I am trying to use threads but I fear I dont understand the implementation.
So, i created a simple example that you can help me with.
I have a simple function which takes a bit of time to finish. while it runs, the rendering is stopped. I instead want the rendering to go on and show me a progress indicator for it.
This is the code that i am using for it:
How can i implement threads so that the backend_logic is run in its own thread without blocking the main thread?
the "progress" variable is a shared one. it is updated every tick in the child thread, but its value should be shown on the main thread.
EDIT:
this is my try.
It doesnt works. :/
I get "Error: main.lua:9: bad argument #1 to 'newThread' (Data expected, got no value)" error. Halp.
EDIT:
If you are looking for the threads example, i am putting that in this section so you dont have to go through other questions and discussions.
Here is my default code.
if you run it, you can see how the window is unresponsive for a few seconds while the logic loop runs. (if you have a non potato PC, you may increase the for loop range so the effect is more prominent)
Code: Select all
debug = true
local progress = 0
local scrWidth = love.graphics.getWidth()
local scrHeight = love.graphics.getHeight()
function love.load(arg)
stime = love.timer.getTime()
backend_logic()
ttime = (love.timer.getTime() - stime)
end
function love.draw(dt)
love.graphics.print("Loading: " .. progress .. " %", scrWidth/2 - 50, scrHeight/2)
love.graphics.print("FPS: "..tostring(love.timer.getFPS( )), 10, 10)
love.graphics.print("Time taken : "..tostring(round(ttime, 1)) .. " seconds", 10, 30)
end
function love.update(dt)
end
function backend_logic()
local smin = 1
local smax = 5000
for i = smin, smax, 1 do
print("ALL WORK AND NO PLAY MAKES JACK A DULL BOY")
progress = round(i * 100 / smax)
end
end
function round(num, dp)
local mult = 10^(dp or 0)
return (math.floor(num * mult + 0.5)) / mult
end
main calls backend as a thread and the backend keeps the main appraised of the current for loop progress via a channel.
main.lua
Code: Select all
debug = true
-- inspect = require "inspect"
local progress = 0
local msg_queue = {}
local scrWidth = love.graphics.getWidth()
local scrHeight = love.graphics.getHeight()
function love.load(arg)
stime = love.timer.getTime()
thread = love.thread.newThread( "backend.lua")
channel = love.thread.getChannel("test" )
thread:start()
ttime = (love.timer.getTime() - stime)
end
function love.draw(dt)
love.graphics.print("Loading: " .. progress .. " %", scrWidth/2 - 50, scrHeight/2)
love.graphics.print("FPS: "..tostring(love.timer.getFPS( )), 10, 10)
love.graphics.print("Time taken : "..tostring(round(ttime, 1)) .. " seconds", 10, 30)
end
function love.update(dt)
progress = channel:pop() or progress
end
function love.threaderror(thread, errorstr)
print("Thread error!\n"..errorstr)
-- thread:getError() will return the same error string now.
end
function get_progress()
return msg_queue[#msg_queue] or "starting..."
end
function round(num, dp)
local mult = 10^(dp or 0)
return (math.floor(num * mult + 0.5)) / mult
end
Code: Select all
local smin = 1
local smax = 1000
channel = love.thread.getChannel("test")
for i = smin, smax, 1 do
print(i .. " > ALL WORK AND NO PLAY MAKES JACK A DULL BOY")
channel:push((i * 100 / smax))
end
function round(num, dp)
local mult = 10^(dp or 0)
return (math.floor(num * mult + 0.5)) / mult
end
Code: Select all
debug = true
local progress = 0
local scrWidth = love.graphics.getWidth()
local scrHeight = love.graphics.getHeight()
function love.load(arg)
stime = love.timer.getTime()
co = coroutine.create(backend_logic)
ttime = (love.timer.getTime() - stime)
end
function love.draw(dt)
love.graphics.print("Loading: " .. progress .. " %", scrWidth/2 - 50, scrHeight/2)
love.graphics.print("FPS: "..tostring(love.timer.getFPS( )), 10, 10)
love.graphics.print("Time taken : "..tostring(round(ttime, 1)) .. " seconds", 10, 30)
end
function love.update(dt)
if coroutine.status(co) ~= "dead" then
_, progress = coroutine.resume(co)
end
end
function backend_logic()
local smin = 1
local smax = 5000
for i = smin, smax, 1 do
print(i .. " > ALL WORK AND NO PLAY MAKES JACK A DULL BOY")
local prg = round(i * 100 / smax)
coroutine.yield(prg)
end
ttime = (love.timer.getTime() - stime)
return 100
end
function round(num, dp)
local mult = 10^(dp or 0)
return (math.floor(num * mult + 0.5)) / mult
end
threads is just as fast as normal blocking operation. However, it feels like threads are meant for long running operations like physics. creating a new thread for every short lived operation may not be ideal. i still need to research this more.
coroutines is definitely slower. the lag becomes more apparent when you increase the for loop range (for small ranges the lag is negligible).
Anyway, if i find any more ways of doing non blocking code (I might try async and some other parallel/concurrent programming libs next) i'll update my thread.
--------------------------------------------------------------
hi
I am trying to use threads but I fear I dont understand the implementation.
So, i created a simple example that you can help me with.
I have a simple function which takes a bit of time to finish. while it runs, the rendering is stopped. I instead want the rendering to go on and show me a progress indicator for it.
This is the code that i am using for it:
Code: Select all
debug = true
local progress = 0
local scrWidth = love.graphics.getWidth()
local scrHeight = love.graphics.getHeight()
function love.load(arg)
stime = love.timer.getTime()
-- thread = love.thread.newThread( backend_logic() )
-- backend_logic()
ttime = (love.timer.getTime() - stime)
end
function love.draw(dt)
love.graphics.print("Loading: " .. progress .. " %", scrWidth/2 - 50, scrHeight/2)
love.graphics.print("FPS: "..tostring(love.timer.getFPS( )), 10, 10)
love.graphics.print("Time taken : "..tostring(round(ttime, 1)) .. " seconds", 10, 30)
end
function love.update(dt)
end
function backend_logic()
local smin = 1
local smax = 10000
for i = smin, smax, 1 do
print("ALL WORK AND NO PLAY MAKES JACK A DULL BOY")
progress = round(i * 100 / smax)
end
end
function round(num, dp)
local mult = 10^(dp or 0)
return (math.floor(num * mult + 0.5)) / mult
end
the "progress" variable is a shared one. it is updated every tick in the child thread, but its value should be shown on the main thread.
EDIT:
this is my try.
Code: Select all
function love.load(arg)
stime = love.timer.getTime()
channel = love.thread.newChannel( )
progress = channel:pop()
thread = love.thread.newThread( backend_logic() )
thread:start()
-- backend_logic()
ttime = (love.timer.getTime() - stime)
end
Code: Select all
function backend_logic()
local prg = 0
local smin = 1
local smax = 1000
for i = smin, smax, 1 do
print("ALL WORK AND NO PLAY MAKES JACK A DULL BOY")
prg = round(i * 100 / smax)
channel:push( prg )
end
end
I get "Error: main.lua:9: bad argument #1 to 'newThread' (Data expected, got no value)" error. Halp.