Josh
Josh

Reputation: 3265

Coroutines, multiple requests in Lua

I've been poring over this subject for the past 12 hours, and I simply cannot seem to get anywhere. I do not even know if this is possible, but I'm hoping it is because it would go a long way to continuing my project.

What I am attempting to do is create coroutines so the particular program I use does not freeze up due to its inability to perform asynchronous http requests. I've figured out how to do that part, even though my understanding of coroutines is still in the "Huh? How does that work?" phase. My issue now is being able to respond to multiple requests with the correct information. For instance, the following should produce three separate responses:

foo(a)
foo(b)
foo(c)

where foo initiates a coroutine with the parameters inside. If all requested separately, then it returns the proper results. However, if requested as a block, it will only return foo(c)'s result. Now, I understand the reasoning behind this, but I cannot find a way to make it return all three results when requested as a block. To help understand this problem a bit, here's the actual code:

function background_weather()
local loc = url.escape(querystring)
weatherpage = http.request("http://api.wunderground.com/api/004678614f27ceae/conditions/q/" .. loc .. ".json")
wresults = json.decode(weatherpage)
--process some stuff here, mainly datamining
end
--send datamined information as a response
coroutine.yield()
end

And the creation of the coroutine:

function getweather ()
-- see if backgrounder running
  if background_task == nil or
   coroutine.status (background_task) == "dead" then
-- not running, create it
   background_task = coroutine.create (background_weather)
-- make timer to keep it going
 AddTimer ("tickler", 0, 0, 1, "",
           timer_flag.Enabled + timer_flag.Replace,
           "tickle_it")
  end  -- if
end -- function

The querystring variable is set with the initial request. I didn't include it here, but for the sake of testing, use 12345 as the querystring variable. The timer is something that the original author of the script initialized to check if the coroutine was still running or not, poking the background every second until done. To be honest, I'm not even sure if I've done this correctly, though it seems to run asynchronously in the program.

So, is it possible to receive multiple requests in one block and return multiple responses, correctly? Or is this far too much a task for Lua to handle?

Upvotes: 2

Views: 3508

Answers (2)

furq
furq

Reputation: 5788

Chapter 9.4 of Programming in Lua contains a fairly good example of how to deal with this exact problem, using coroutines and LuaSocket's socket.select() function to prevent busylooping.

Unfortunately I don't believe there's any way to use the socket.http functions with socket.select; the code in the PiL example is often all you'll need, but it doesn't handle some fairly common cases such as the requested URL sending a redirect.

Upvotes: 1

kikito
kikito

Reputation: 52641

Coroutines don't work like that. They are, in fact, blocking.

The problem coroutines resolve is "I want to have a function I can execute for a while, then go back to do other thing, and then come back and have the same state I had when I left it".

Notice that I didn't say "I want it to keep running while I do other things"; the flow of code "stops" on the coroutine, and only continues on it when you go back to it.

Using coroutines you can modify (and in some cases facilitate) how the code behaves, to make it more evident or legible. But it is still strictly single-threaded.

Remember that what Lua implements must be specified by C99. Since this standard doesn't come with a thread implementation, Lua is strictly single-threaded by default. If you want multi-threading, you need to hook it to an external lib. For example, luvit hooks Luajit with the libuv lib to achieve this.

A couple good references:

Upvotes: 5

Related Questions