Skip to content

ThreadPool no longer creates new threads to compensate for threads sleeping on futures #139

Merged
merged 20 commits into from Nov 9, 2012

2 participants

@michaeljbishop

This is an interesting, but still experimental version of the ThreadPool in
which the thread pool no longer needs to create new threads to
compensate for the imminent sleep of a thread on a future.

Previously, the ThreadPool created futures and added them to the queue.
If, when they processed a future and they had to wait for it to
finish executing, they would spawn another thread so they could
wait for the future.

Now, a non-blocking attempt to process the future's block is what is
put on the queue and a blocking attempt is passed back from #future.
In this way, the thread pool is free to process the core of a future
by dequeuing it and calling it. The the thread can't get the lock, it
is assumed that another thread is handling it and so it moves to
the next.

michaeljbishop and others added some commits Oct 24, 2012
@michaeljbishop michaeljbishop Added some instrumentation to retieve stats from the threadpool
Two new methods to ThreadPool:

1 - #__begin_stats__
This turns on stat-keeping. You can only call it once.

2 - #__stats__
Retrieves all the current statistics. Locks the stats array while it
makes a duplicate. Best to call after #join.
a89a68d
@michaeljbishop michaeljbishop Merge branch 'master' of https://github.com/jimweirich/rake into no-s…
…leep-thread-pool

Conflicts:
	lib/rake/thread_pool.rb
2c04017
@michaeljbishop michaeljbishop Merge branch 'master' into no-sleep-thread-pool 93d3144
@michaeljbishop michaeljbishop ThreadPool threads no longer sleep on futures.
Previously, the ThreadPool created futures and added them to the queue.
If, when they processed a future and they had to wait for it to
finish executing, they would spawn another thread so they could
wait for the future.

Now, a non-blocking attempt to process the future's block is what is
put on the queue and a blocking attempt is passed back from #future.
In this way, the thread pool is free to process the core of a future
by dequeuing it and calling it. The the thread can't get the lock, it
is assumed that another thread is handling it and so it moves to
the next.
07272c4
@jimweirich add private_reader support 2053d6b
@jimweirich Merge branch 'master' of https://github.com/michaeljbishop/rake into …
…threadstats

* 'master' of https://github.com/michaeljbishop/rake:
  Sped up #stat sampling.
  Fixed the ThreadPool statistics code to maintain compatibility with 1.8.7.
bc546be
@jimweirich move dot to end of previous line
to maintain compatibility with Ruby 1.8
a467228
@jimweirich made the test less order dependent 841200e
@jimweirich Merge branch 'no-sleep-thread-pool' of https://github.com/michaeljbis…
…hop/rake into newpool

* 'no-sleep-thread-pool' of https://github.com/michaeljbishop/rake:
  ThreadPool threads no longer sleep on futures.
  Added some instrumentation to retieve stats from the threadpool
be8e4ad
@jimweirich improve order independence in test e768ae7
@jimweirich add promise_complete? method 8bf696d
@jimweirich whitespace a3ed6a4
@jimweirich more with promise_complete? 7d90f8b
@jimweirich should use value for futures (not call) 5afbc00
@jimweirich add comment to assert 8dcd41a
@jimweirich add ThreadPool::Promise d658fc8
@jimweirich de-lambda-fied the promise object. 57df3f4
@jimweirich
Owner

I've locally merged the new pool changes. In going over the code, I really felt that the promise should be its own object instead of a bunch of lambdas. I created a Promise object, originally just to contain the lambdas, but as I kept refactoring the lambdas eventually melted away.

I'm fairly happy with the result and feel I have a better grasp on how the threading / future / promise model is working.

The result is in the newpool branch. Take a look. If everything seems ok, I will merge this into master.

@michaeljbishop
@michaeljbishop
michaeljbishop added some commits Nov 3, 2012
@jimweirich
Owner

Re: chore ... Yes, I originally called it core for the lambda, but at some point the name slipped out.

I'm away from my laptop at the moment, I'll review the changes later tonight.

Quick question about thread life time ... Looks like the threads voluntarily die if the queue is empty. This works because adding a new item to the queue tries to start a new thread. First, is my understanding correct? If so. What do you think about keeping the thread around until the entire job is done, rather than trying to shrink the pool? Currently the code seems to have the potential to shrink/grow/shrink/grow. Just thinking out loud, and maybe that's not a big concern. Thoughts welcome.

@michaeljbishop
@jimweirich jimweirich merged commit 02663c2 into jimweirich:master Nov 9, 2012

1 check passed

Details default The Travis build passed
@jimweirich
Owner

Hmm, just a note. I was testing with Rubinius and discovered that TestRakeTestThreadPool#test_pool_join_empties_queue will occasionally hang when running under Rubinius. I haven't investigated any further than that. Care to take a look?

@michaeljbishop
@jimweirich
Owner

The deadlock problem may be an issue with Rubinius. I've updated to the current head and haven't had a deadlock since then. There was a deadlock issue that was addressed in rubinius/rubinius@03a475f.

So, if you're not seeing anything, that might be why.

@jimweirich
Owner

I just ran 50 itereations of the tests with the latest master of Rubinius (with commit 52eba5f). I got no crashes and no deadlocks.

@michaeljbishop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.