Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pool#join not working ? #6

Closed
Kris-LIBIS opened this issue Jun 27, 2013 · 11 comments · Fixed by #7
Closed

Pool#join not working ? #6

Kris-LIBIS opened this issue Jun 27, 2013 · 11 comments · Fixed by #7

Comments

@Kris-LIBIS
Copy link
Contributor

Hi,

Isn't the following supposed to work:

require 'thread/pool'
require 'securerandom'

pool = Thread.pool(0,4)
pool.auto_trim!

1.upto(40).each do |x|
  pool.process do
    sleep 1 + SecureRandom.random_number * 2
    print ''.concat(x + 32)
    $stdout.flush
  end
end

pool.join

With MRI 2.0 I get:

#"$%!&)'(*+-,/0.12543679:8;=><?AB@EDCHFG

/home/kris/.rvm/gems/ruby-2.0.0-p195/gems/thread-0.0.8.1/lib/thread/pool.rb:254:in `join': No live threads left. Deadlock?
    from /home/kris/.rvm/gems/ruby-2.0.0-p195/gems/thread-0.0.8.1/lib/thread/pool.rb:254:in `join'
    from test1.rb:15:in `<main>'

With JRuby 1.7.4, it hangs. I added some prints where Threads are created and closed and I noticed that threads are only created, never closed.

I found one line, which contains a bug, I think. In Pool#trim I replaced

@trim_requests -= 1

with

@trim_requests += 1

and that helped, but unfortunately only partially. In JRuby I now see that 4 threads are created and 3 of them are closed.
As I was hacking my way aound the code, I also modified Pool#join into:

    def join
        until @workers.empty?
            if worker = @workers.first
                worker.join 0.1
                trim
            end
        end

        self
    end

and that works. I know it defeats your initial purpose of not consuming CPU during waits, so I'd love to get rid of the join timeout, but I cannot see how.

@meh
Copy link
Owner

meh commented Jun 27, 2013

Yeah, that solution is unacceptable, I know about the issue on MRI, it's a bug in the deadlock inference, I opened a bug on Ruby's issue tracker but I was unable to come up with a reduced testcase, so they ignored it.

I'll try to find a proper solution, but it really isn't easy, pools are supposed to be used in long running applications rather than to achieve parallelization in simple scripts.

@meh
Copy link
Owner

meh commented Jun 27, 2013

No wait, now that I think of it, you should use #shutdown and not #join there, the pool is never going to be closed if you join.

I think I should make #join private, or work differently, as in "wait for all the tasks to be consumed", what do you think?

@Kris-LIBIS
Copy link
Contributor Author

The wait for all the tasks to be consumed is actually what I wanted to achieve.

I have a batches of workload that comes in at irregular times. Each batch should be handled in different stages. I need to be sure that a batch has finished stage 1 completely before I start with stage 2. Then stage 3 and so on. When the batch is completely processed, it will wait for the next batch.

I want to use the same Pool for stage 1, stage 2, stage 3, .... which is why I cannot call shutdown. Actually, I wanted to have 4 threads minimum with a max of up to 20 threads, but - of course - any minimum not 0 does not work with join.

I'm actually wondering what the join method is supposed to do, currently? AFAIK it will just hang. I replaced worker.join with a simple sleep(0.3) and trim and that works just as well. worker.join seems to never return.

@Kris-LIBIS
Copy link
Contributor Author

I've forked the code and trying to implement a wait that returns when (@todo.empty? and @waiting == @Spawned). That should do the trick, not?

@meh
Copy link
Owner

meh commented Jun 27, 2013

#join right now is useful if you call #shutdown! and want to wait for the workers to end and it's used internally by #shutdown.

So yes, it's kind of useless and not what you want as is.

I think the best way to go is to merge the current #join in #shutdown and make #join wait for the current tasks to finish.

Depending on how you implement the waiting, having @todo.empty? && @waiting == @spawned should be a good check.

@Kris-LIBIS
Copy link
Contributor Author

OK. I'll have a go. I'll let you know when I'm done.

@Kris-LIBIS
Copy link
Contributor Author

BTW. Do you agree that the @trim_requests -= 1 is a bug? Or am I mistaken?

@meh
Copy link
Owner

meh commented Jun 27, 2013

You're mistaken, the number of trim requests is decreased when one of the workers is closed, if you increment it all the workers will die.

@Kris-LIBIS
Copy link
Contributor Author

Are you sure? I was talking about the line in the #trim method. Shouldn't the trim_requests go up when a new trim request is made?

@Kris-LIBIS
Copy link
Contributor Author

Auto_trim did not work for me unless I changed that line to += ...

@meh
Copy link
Owner

meh commented Jun 27, 2013

Oh, yeah, I'm sorry, you're right, I was looking in the worker instead of #trim.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants