user1065985
user1065985

Reputation:

How to return a value to a function then starts a thread in the same function?

Is there a way for return a value to a function, then invoking a thread in that function? For example:

def foo
  return fast_function
  Thread.new do
    slow_function
  end
end

The reason behind this is that both fast_function and slow_function write to the same resource. But I want to ensure that fast_function runs and complete first, and return its value to foo before slow_function writes to the shared resource. There are some cases where slow_function completes before fast_function and I am hit with a race condition.

EDIT: More context on the problem. This is related to server-side events I am trying to implement. I am trying to get fast_function to compute an event id and return and html. While slow_function is responsible for notifying the client via event id that the process is done. However, in some cases, slow_function notifies the client before the client event know where to listen, because fast_function did not return the event id yet.

Upvotes: 1

Views: 247

Answers (1)

B.G.
B.G.

Reputation: 6026

No, a return will exit the function, it would also exit the function in a yield block. In my opinions there are multiple solutions to this problem.

Actually it would be a perfect fit for a Promise of Concurrent Ruby (https://github.com/ruby-concurrency/concurrent-ruby)

you could use it somewhat like this:

def foo

   fast = Concurrent::Promise.execute{ fast_function }
   slow = promises[:fast].then{ slow_function }
                         .on_fullfill{ notify_client }
   return fast.value
end

As you can guess it will return the value of your fast function. But it will also call the on_fullfill function (Or a proc) if the slow function has finished. And the most important, it will guarante order.

NOTE: I am not sure if I understood you correctly, if you want to start booth threads at the same time, but ensure that the fast one has finished first. you can do something like this:

fast = Concurrent::Promise.execute{ fast_function }
slow = Concurrent::Promise.execute{ slow_function }

render fast.value # Or what you ever do with the html. 
                  #.value will wait for the Promise to finish.
result slow = slow.value

This way you would start booth functions parallel, but be sure you would get the answer first for the fast one.


Edit 1: I thougth about this, and I am not really sure if you want to have an asynchronous task at all. It is hard to tell since you posted a minimal example (what is correct of coruse). If you just want to have a function which returns botth function returns in the right order, you could just do a yield:

def foo
  yield fast_function
  yield slow_function
end

Upvotes: 1

Related Questions