Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>For your main question:</p> <p>If you're doing something more complex than this—or, in particular, if you're doing this repeatedly—you probably want a "thread group" class. There are dozens of them pre-made, but it's pretty trivial to write one yourself if you don't like any of them.</p> <p>Then, instead of this:</p> <pre><code>threadList = [] for argchunk in splitIntoChunks(values, 10): threadList.append(threading.Thread(target=myThreadFunc, args=argchunk)) ... someTotal = 0 for th in threadList: th.join() someTotal += th.resultsAttribute </code></pre> <p>You can do this:</p> <pre><code>threadGroup = ThreadGroup.ThreadGroup() for argchunk in splitIntoChunks(values, 10): threadGroup.newThread(myThreadFunc, argchunk) threadGroup.join() someTotal = sum(th.resultsAttribute for th in threadGroup) </code></pre> <p>Or, maybe even better, a full thread pool library, so you can do this:</p> <pre><code>pool = ThreadPool(10) for argchunk in splitIntoChunks(values, 100): pool.putRequest(myThreadFunc, argchunk) pool.wait() </code></pre> <p>The advantage here is that you can just as easily have 100 jobs scheduled as appropriate on 10 threads, instead of 10 jobs one per thread, without all the work of maintaining a queue, etc. The disadvantage is that you can't just iterate threads to get the return values, you have to iterate jobs—and ideally, you don't want to keep the jobs alive until the end just so you can iterate them.</p> <p>Which brings us to your second question, how to get values out of the threads (or jobs). There are many, many ways to do this.</p> <p>What you've done works. You don't even need any locking.</p> <p>Using callbacks, as you suggested, also works. But keep in mind that the callback will run on the worker thread, not the main thread, so if it's accessing some global object, you will need some kind of synchronization.</p> <p>If you're going to synchronize anyway, there may not be any benefit to the callbacks. For example, if all you're trying to do is sum a bunch of values, you can just set <code>total=[0]</code>, and have each thread just do <code>total[0] += myValue</code> inside a lock. (Of course in this case, it probably makes more sense to just do the summing in the main thread and avoid the lock, but if the work of amalgamating the results is much heftier, that choice may not be as simple.)</p> <p>You can also use an atomic object of some kind, instead of locking explicitly. For example, the standard Queue.Queue and collections.deque are both atomic, so each thread can just set <code>q = Queue.Queue()</code>, then each thread pushes its result by doing <code>q.push(myValue)</code>, then after joining you just iterate and sum up the queue's values.</p> <p>In fact, if each thread is pushing to the queue exactly once, you can just do 10 blocking gets on the queue itself, after which you know that the <code>group.join()</code> or <code>pool.wait()</code> or whatever will return quickly.</p> <p>Or you can even push callbacks as jobs onto a queue. Again, you can do 10 blocking gets on the queue, executing the result each time.</p> <p>If each thread can return multiple objects, they can push a sentinel value or callback onto the queue when they're done, and your main thread keeps popping until it reads 10 sentinels.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload