starting multiple process in multiple threads elixir - multithreading

I am simply doing few operations against a list of servers from db as
list_servers()
|> Enum.map(fn(server) ->
go_through_and_email(server)
end)
my only question is that, is there any possibility to start each go_through_email(server) process for each server, separately? Right now, It gets completed for the first one and then goes to the 2nd one. Can we run them parallelly? as list_servers could have 100 or 100+ objects.
I don't want to use Task.await or Task.async, are there any other options to explore?

You can use Task.async_stream/3. It allows you to pass an enumerable and run a function on them, with an option to limit the maximum number of tasks to run in parallel using the max_concurrency option. The default timeout is 5000ms, you'll probably want to specify a larger one.
Here's a small example:
1..20
|> Task.async_stream(fn x ->
:timer.sleep(1000)
x
end, max_concurrency: 4, timeout: 10_000)
|> Enum.each(&IO.inspect/1)
If you run this, you should see {:ok, 1} to {:ok, 20} printed in batches of 4 every second. The whole thing should finish in 5 seconds, as expected when running a 1 second sleep in batches of 4 for 20 items.

You can use GenServer as well. If list_servers() and go_through_and_email() will be defined as helper functions you should be able to do something like this:
defmodule ExampleGenServer do
use GenServer
## Client API
def start_link(name) do
GenServer.start_link(__MODULE__, [], name: name)
end
def go_through(name) do
GenServer.cast(name, {:go_through, name})
end
## Server API / Callbacks
def init(initial_state) do
{:ok, initial_state}
end
def handle_cast({:go_through, name}, state) do
state = go_through_and_email(server)
{:noreply, state}
end
def handle_info({:some_info}, state) do
# stuff
{:noreply, state}
end
## Helper functions
defp list_servers() do
# stuff
end
defp go_through_and_email() do
# stuff
end
end
Then you could create new instance of GenServer in a loop:
list_servers()
|> Enum.map(fn(server) ->
ExampleGenserver.start_link(server)
end)
I've made it quickly during a break so I could miss / mess up something ;)
If you will need some additional details about GenServers you may refer to my Gist. It describes GenServer client / server API, messaging and arg passing ;)
And one more thing, remember about GenServer teardown! ;)

One thing you can do is to use Task.start, but you don't want to use Task module.
Another thing is to get rid of go_through_email(server) in the Enum.map. Assuming that server is DB Server, you should create a GenServers that will communicate with DB servers and in the map you would send a message to each of the GenServers.
Enum.map(list_of_gen_servers, &send_message_to_go_through_email(&1))
And then every GenServer would handle the code in the parallel. Of course you would need to have the list of GenServers prepared. It's definitely better approach than using send / receive explicitly.
Edit:
Task module would be great if you want to fire and forget. GenServers would be better choice, if you would frequently access DB servers and they allow to have full control how the communication model should looks like.

You can also defer the real task to another supervisor. I can't decide whether a simple function or a gen server is needed in your case, but have a look at simple_one_for_one supervisor.
This kind of supervisor is a perfect fit for this kind of needs (sending emails, if I got it correctly).
PS. You said no Task, but playing with Task.async_stream and timeouts is another fit option too.

Related

How do I retrieve data from a Django DB before sending off Celery task to remote worker?

I have a celery shared_task that is scheduled to run at certain intervals. Every time this task is run, it needs to first retrieve data from the Django DB in order to complete the calculation. This task may or may not be sent to a celery worker that is on a separate machine, so in the celery task I can't make any queries to a local celery database.
So far I have tried using signals to accomplish it, since I know that functions with the wrapper #before_task_publish are executed before the task is even published in the message queue. However, I don't know how I can actually get the data to the task.
#shared_task
def run_computation(data):
perform_computation(data)
#before_task_publish.connect
def receiver_before_task_publish(sender=None, headers=None, body=None, **kwargs):
data = create_data()
# How do I get the data to the task from here?
Is this the right way to approach this in the first place? Or would I be better off making an API route that the celery task can get to retrieve the data?
I'm posting the solution that worked for me, thanks for the help #solarissmoke.
What works best for me is utilizing Celery "chain" callback functions and separate RabbitMQ queues for designating what would be computed locally and what would be computed on the remote worker.
My solution looks something like this:
#app.task
def create_data_task():
# this creates the data to be passed to the analysis function
return create_data()
#app.task
def perform_computation_task(data):
# This performs the computation with given data
return perform_computation(data)
#app.task
def store_results(result):
# This would store the result in the DB here, but for now we just print it
print(result)
#app.task
def run_all_computation():
task = signature("path.to.tasks.create_data_task", queue="default") | signature("path.to.tasks.perform_computation_task", queue="remote_computation") | signature("path.to.tasks.store_results", queue="default")
task()
Its important to note here that these tasks were not run serially; they were in fact separate tasks that are run by the workers and therefore do not block a single thread. The other tasks are only activated by a callback function from the others. I declared two celery queues in RabbitMQ, a default one called default, and one specifically for remote computation called "remote_computation". This is described explicitly here including how to point celery workers at created queues.
It is possible to modify the task data in place, from the before_task_publish handler, so that it gets passed to the task. I will say upfront that there are many reasons why this is not a good idea:
#before_task_publish.connect
def receiver_before_task_publish(sender=None, headers=None, body=None, **kwargs):
data = create_data()
# Modify the body of the task data.
# Body is a tuple, the first entry of which is a tuple of arguments to the task.
# So we replace the first argument (data) with our own.
body[0][0] = data
# Alternatively modify the kwargs, which is a bit more explicit
body[1]['data'] = data
This works, but it should be obvious why it's risky and prone to breakage. Assuming you have control over the task call sites I think it would be better to drop the signal altogether and just have a simple function that does the work for you, i.e.,:
def create_task(data):
data = create_data()
run_computation.delay(data)
And then in your calling code, just call create_task(data) instead of calling the task directly (which is what you presumably do right now).

Running a task on a timer

I'd like to create a program that runs a function on an interval. I'm still very new to Elixir and do not know really where to start with this. My idea is that since we can use GenServer to create a program to sit and wait in a loop for messages, I could provide it a message (maybe :kick) and when it receives this message it would run the function.
However, that leaves one problem - how do I kick it without a cron job? Can I fire up a thread and run a timer that kicks it on an interval? If the main thread dies - is there an easy way to be notified and restart it?
Thank you!
You can use timer:send_interval/2 with a GenServer. You'll need to call the function from the init/1 callback and then handle the tick messages from the handle_info callback. Here's an example that prints 0, 1, 2, ... every second:
defmodule A do
use GenServer
def init(_) do
:timer.send_interval(1000, :tick)
{:ok, 0}
end
def handle_info(:tick, state) do
IO.inspect state
{:noreply, state + 1}
end
end
iex(1)> GenServer.start_link(A, [])
{:ok, #PID<0.94.0>}
0
1
2
3
4
...
If the main thread dies - is there an easy way to be notified and restart it?
You should look into Supervisors. The GenServer above can be added as a "worker" to a Supervisor. The Supervisor can handle restarting the GenServer if it exits for any reason.
#Dogbert mentionned using using the send_interval function from Erlang, which would be used like so : :timer.send_interval(milliseconds, process, message).
A quick Google search however, netted me the quantum-elixir library which appears to be capable of cron like scheduling, as well as scheduling tasks at runtime.

Making a threading system in lua

So I have been working with coroutines for a little while and I'm sort of having trouble trying to make what I want. I want a class that I can access objectivley creating objects as tasks or processes. I think showing you code would be irrelevant and its not what I want either. So I'm just going to show you how i want the functionality
local task1 = Tasker.newTask(function()
while true do
print("task 1")
end
end)
local task2 = Tasker.newTask(function()
while true do
print("task 2")
end
end)
task1:start()
task2:start()
This way I can run multiple tasks at once, I want to be able to add new tasks when ever during runtime. Also I would like a way to stop the tasks also for example:
task2:stop()
But I don't want the stop command to entirely delete the task instance, only stop the task itself so I can invoke
task2:start()
Then maybe I could use a command to delete it.
task2:delete()
This would be very helpful and thank you for help if you need more info please ask. Also i posted this on my phone so there may be typos and formatting issues
Lua doesn't natively support operating system threads, i.e. preemptive multitasking.
You can use coroutines to implement your own cooperative "threads", but each thread must relinquish control before another can do anything.
local task1 = Tasker.newTask(function()
while true do
print("task 1")
coroutine.yield()
end
end)
local task2 = Tasker.newTask(function()
while true do
print("task 2")
coroutine.yield()
end
end)
Your Tasker class must take the task function and wrap it in a coroutine, then take care of calling coroutine.resume on them. Operations like stop and start would set flags on the task that tell Tasker whether or not to resume that particular coroutine in the main loop.
You can do this via C. You might be able to use LuaLanes and Linda objects.

Is there a way to use cherrypy's Monitor to perform a single task and then stop?

I have a web application that requests a report that takes more than 10 minutes to run. Apart from improving that performance, I would for now prefer to set up a thread to run the report and mail it to the user, returning that decision message back to the user immediately.
I have been looking at cherrypy.process.plugins.Monitor, but I'm not clear if it is the correct choice (what to do with the frequency parameter?)
Monitor is not the correct choice; it's for running the same task repeatedly on a schedule. You're probably better off just calling threading.Thread(target=run_report).start(). You can then return 202 Accepted to the user, along with a URL for the client to watch the status and/or retrieve the newly-created report resource when it's ready.
The one caveat to that is that you might want your new thread to shut down gracefully when the cherrypy.engine stops. Have a look at the various plugins for examples of how to hook into the 'stop' channel on the bus. The other option would be to make your thread daemonic, if you don't care if it terminates abnormally.
Besides agreeing with fumanchu's answer, I would like to add that the frequency parameter is actually the period expressed in seconds.cherrypy.process.plugins.Monitor (the name is misleading).
Another possible solution could be having a monitor executed periodically, and a set of working computations which can be checked periodically for completion. The code would be something like
class Scheduler:
def __init__ (self):
self.lock = threading.Lock()
self.mon = Monitor(cherrypy.engine, check_computations, frequency=whatever)
self.mon.start()
self.computations = list() # on which we append stuff
def check_computations (self):
with self.lock:
for i in self.computations:
check(i) # Single check function
Caveats:
The computation time of check matters. You don't want to have workload on this perioic routine
Beware on how you use locks:
It is protecting the computations list;
If you access it (even indirectly) from with check your program gets into deadlock. This could be the case if you want to unsubscribe something from the computations list.

What multithreading package for Lua "just works" as shipped?

Coding in Lua, I have a triply nested loop that goes through 6000 iterations. All 6000 iterations are independent and can easily be parallelized. What threads package for Lua compiles out of the box and gets decent parallel speedups on four or more cores?
Here's what I know so far:
luaproc comes from the core Lua team, but the software bundle on luaforge is old, and the mailing list has reports of it segfaulting. Also, it's not obvious to me how to use the scalar message-passing model to get results ultimately into a parent thread.
Lua Lanes makes interesting claims but seems to be a heavyweight, complex solution. Many messages on the mailing list report trouble getting Lua Lanes to build or work for them. I myself have had trouble getting the underlying "Lua rocks" distribution mechanism to work for me.
LuaThread requires explicit locking and requires that communication between threads be mediated by global variables that are protected by locks. I could imagine worse, but I'd be happier with a higher level of abstraction.
Concurrent Lua provides an attractive message-passing model similar to Erlang, but it says that processes do not share memory. It is not clear whether spawn actually works with any Lua function or whether there are restrictions.
Russ Cox proposed an occasional threading model that works only for C threads. Not useful for me.
I will upvote all answers that report on actual experience with these or any other multithreading package, or any answer that provides new information.
For reference, here is the loop I would like to parallelize:
for tid, tests in pairs(tests) do
local results = { }
matrix[tid] = results
for i, test in pairs(tests) do
if test.valid then
results[i] = { }
local results = results[i]
for sid, bin in pairs(binaries) do
local outcome, witness = run_test(test, bin)
results[sid] = { outcome = outcome, witness = witness }
end
end
end
end
The run_test function is passed in as an argument, so a package can be useful to me only if it can run arbitrary functions in parallel. My goal is enough parallelism to get 100% CPU utilization on 6 to 8 cores.
Norman wrote concerning luaproc:
"it's not obvious to me how to use the scalar message-passing model to get results ultimately into a parent thread"
I had the same problem with a use case I was dealing with. I liked lua proc due to its simple and light implementation, but my use case had C code that was calling lua, which was triggering a co-routine that needed to send/receive messages to interact with other luaproc threads.
To achieve my desired functionality I had to add features to luaproc to allow sending and receiving messages from the parent thread or any other thread not running from the luaproc scheduler. Additionally, my changes allow using luaproc send/receive from coroutines created from luaproc.newproc() created lua states.
I added an additional luaproc.addproc() function to the api which is to be called from any lua state running from a context not controlled by the luaproc scheduler in order to set itself up with luaproc for sending/receiving messages.
I am considering posting the source as a new github project or contacting the developers and seeing if they would like to pull my additions. Suggestions as to how I should make it available to others are welcome.
Check the threads library in torch family. It implements a thread pool model: a few true threads (pthread in linux and windows thread in win32) are created first. Each thread has a lua_State object and a blocking job queue that admits jobs added from the main thread.
Lua objects are copied over from main thread to the job thread. However C objects such as Torch tensors or tds data structures can be passed to job threads via pointers -- this is how limited shared memory is achieved.
This is a perfect example of MapReduce
You can use LuaRings to accomplish your parallelization needs.
Concurrent Lua might seem like the way to go, but as I note in my updates below, it doesn't run things in parallel. The approach I tried was to spawn several processes that execute pickled closures received through the message queue.
Update
Concurrent Lua seems to handle first-class functions and closures without a hitch. See the following example program.
require 'concurrent'
local NUM_WORKERS = 4 -- number of worker threads to use
local NUM_WORKITEMS = 100 -- number of work items for processing
-- calls the received function in the local thread context
function worker(pid)
while true do
-- request new work
concurrent.send(pid, { pid = concurrent.self() })
local msg = concurrent.receive()
-- exit when instructed
if msg.exit then return end
-- otherwise, run the provided function
msg.work()
end
end
-- creates workers, produces all the work and performs shutdown
function tasker()
local pid = concurrent.self()
-- create the worker threads
for i = 1, NUM_WORKERS do concurrent.spawn(worker, pid) end
-- provide work to threads as requests are received
for i = 1, NUM_WORKITEMS do
local msg = concurrent.receive()
-- send the work as a closure
concurrent.send(msg.pid, { work = function() print(i) end, pid = pid })
end
-- shutdown the threads as they complete
for i = 1, NUM_WORKERS do
local msg = concurrent.receive()
concurrent.send(msg.pid, { exit = true })
end
end
-- create the task process
local pid = concurrent.spawn(tasker)
-- run the event loop until all threads terminate
concurrent.loop()
Update 2
Scratch all of that stuff above. Something didn't look right when I was testing this. It turns out that Concurrent Lua isn't concurrent at all. The "processes" are implemented with coroutines and all run cooperatively in the same thread context. That's what we get for not reading carefully!
So, at least I eliminated one of the options I guess. :(
I realize that this is not a works-out-of-the-box solution, but, maybe go old-school and play with forks? (Assuming you're on a POSIX system.)
What I would have done:
Right before your loop, put all tests in a queue, accessible between processes. (A file, a Redis LIST or anything else you like most.)
Also before the loop, spawn several forks with lua-posix (same as the number of cores or even more depending on the nature of tests). In parent fork wait until all children will quit.
In each fork in a loop, get a test from the queue, execute it, put results somewhere. (To a file, to a Redis LIST, anywhere else you like.) If there are no more tests in queue, quit.
In the parent fetch and process all test results as you do now.
This assumes that test parameters and results are serializable. But even if they are not, I think that it should be rather easy to cheat around that.
I've now built a parallel application using luaproc. Here are some misconceptions that kept me from adopting it sooner, and how to work around them.
Once the parallel threads are launched, as far as I can tell there is no way for them to communicate back to the parent. This property was the big block for me. Eventually I realized the way forward: when it's done forking threads, the parent stops and waits. The job that would have been done by the parent should instead be done by a child thread, which should be dedicated to that job. Not a great model, but it works.
Communication between parent and children is very limited. The parent can communicate only scalar values: strings, Booleans, and numbers. If the parent wants to communicate more complex values, like tables and functions, it must code them as strings. Such coding can take place inline in the program, or (especially) functions can be parked into the filesystem and loaded into the child using require.
The children inherit nothing of the parent's environment. In particular, they don't inherit package.path or package.cpath. I had to work around this by the way I wrote the code for the children.
The most convenient way to communicate from parent to child is to define the child as a function, and to have the child capture parental information in its free variables, known in Lua parlances as "upvalues." These free variables may not be global variables, and they must be scalars. Still, it's a decent model. Here's an example:
local function spawner(N, workers)
return function()
local luaproc = require 'luaproc'
for i = 1, N do
luaproc.send('source', i)
end
for i = 1, workers do
luaproc.send('source', nil)
end
end
end
This code is used as, e.g.,
assert(luaproc.newproc(spawner(randoms, workers)))
This call is how values randoms and workers are communicated from parent to child.
The assertion is essential here, as if you forget the rules and accidentally capture a table or a local function, luaproc.newproc will fail.
Once I understood these properties, luaproc did indeed work "out of the box", when downloaded from askyrme on github.
ETA: There is an annoying limitation: in some circumstances, calling fread() in one thread can prevent other threads from being scheduled. In particular, if I run the sequence
local file = io.popen(command, 'r')
local result = file:read '*a'
file:close()
return result
the read operation blocks all other threads. I don't know why this is---I assume it is some nonsense going on within glibc. The workaround I used was to call directly to read(2), which required a little glue code, but this works properly with io.popen and file:close().
There's one other limitation worth noting:
Unlike Tony Hoare's original conception of communicating sequential processing, and unlike most mature, serious implementations of synchronous message passing, luaproc does not allow a receiver to block on multiple channels simultaneously. This limitation is serious, and it rules out many of the design patterns that synchronous message-passing is good at, but it's still find for many simple models of parallelism, especially the "parbegin" sort that I needed to solve for my original problem.

Resources