@Guido: I agree, that’s a much cleaner solution to pass the executor.  However, 
I think the last line should be future.add_done_callback(callback)
return newf 

not executor.submit.  

I’ll rewrite it like this and resubmit tonight for discussion.

Sent from my iPhone

> On Jan 26, 2018, at 11:59 AM, Guido van Rossum <gu...@python.org> wrote:
> 
> @Bar: I don't know about exposing _chain_future(). Certainly it's overkill 
> for what the OP wants -- their PR only cares about chaining 
> concurrent.future.Future.
> 
> @Daniel: I present the following simpler solution -- it requires you to 
> explicitly pass the executor, but since 'fn' is being submitted to an 
> executor, EIBTI.
> 
> def then(executor, future, fn):
>     newf = concurrent.futures.Future()
>     def callback(fut):
>         f = executor.submit(fn, fut)
>         try:
>             newf.set_result(f.result())
>         except CancelledError:
>             newf.cancel()
>         except Exception as err:
>             newf.set_exception(err)
>     return executor.submit(callback)
> 
> I can't quite follow your reasoning about worker threads (and did you realize 
> that because of the GIL, Python doesn't actually use multiple cores?). But I 
> suppose it doesn't matter whether I understand that -- your point is that you 
> want the 'fn' function submitted to the executor, not run as a "done 
> callback". And that's reasonable. But modifying so much code just so the 
> Future can know which to executor it belongs so you can make then() a method 
> seems overkill.
> 
>> On Fri, Jan 26, 2018 at 8:54 AM, Daniel Collins <dancollin...@gmail.com> 
>> wrote:
>> So, just going point by point:
>> 
>> Yes, absolutely put this off for 3.8. I didn’t know the freeze was so close 
>> or I would have put the 3.8 tag on originally.
>> 
>> Yes, absolutely it is only meant for concurrent.futures futures, it only 
>> changes async where async uses concurrent.futures futures.
>> 
>> Here’s a more fleshed out description of the use case:
>> 
>> Assume you have two functions. Function a(x: str)->AResult fetches an 
>> AResult object from a web resource, function b(y: AResult) performs some 
>> computationally heavy work on AResult.
>> 
>> Assume you’re calling a 10 times with a threadpoolexecutor with 2 worker 
>> theads.  If you were to schedule a as future using submit, and b as a 
>> callback, the executions would look like this:
>> 
>> ExecutorThread: b*10
>> Worker1: a*5
>> Worker2: a*5
>> 
>> This only gets worse as more work (b) is scheduled as a callback for the 
>> result from a.
>> 
>> Now you could resolve this by, instead of submitting b as a callback, 
>> submitting the following lambda:
>> 
>> lambda x: executor.submit(b, x) 
>> 
>> But then you wouldn’t have easy access to this new future. You would have to 
>> build a lot of boilerplate code to collect that future into some external 
>> collection, and this would only get worse the deeper the nesting goes.
>> 
>> With this syntax on the other hand, if you run a 10 times using submit, but 
>> then run a_fut.then(b) for each future, execution instead looks like this:
>> 
>> ExecutorThread: 
>> Worker1: a*5 b*5
>> Worker2: a*5 b*5
>> 
>> You can also do additional depth easily. Suppose you want to run 3 c 
>> operations (processes the output of b) for each b operation. Then you could 
>> call this like
>> 
>> b_fut = a_fut.then(b)
>> 
>> for i in range(3):
>>     b_fut.then(c)
>> 
>> And the execution would look like this:
>> 
>> ExecutorThread:
>> Worker1: a*5 b*5 c*15
>> Worker2: a*5 b*5 c*15
>> 
>> Which would be very difficult to do otherwise, and distributes the load 
>> across the workers, while having direct access to the outputs of the calls 
>> to c.
>> 
>> -dancollins34
>> 
>> Sent from my iPhone
>> 
>>> On Jan 26, 2018, at 1:07 AM, Guido van Rossum <gu...@python.org> wrote:
>>> 
>>> I really don't want to distract Yury with this. Let's consider this (or 
>>> something that addresses the same need) for 3.8.
>>> 
>>> To be clear this is meant as a feature for concurrent.futures.Future, not 
>>> for asyncio.Future. (It's a bit confusing since you also change asyncio.)
>>> 
>>> Also to be honest I don't understand the use case *or* the semantics very 
>>> well. You have some explaining to do...
>>> 
>>> (Also, full links: https://bugs.python.org/issue32672; 
>>> https://github.com/python/cpython/pull/5335)
>>> 
>>>> On Thu, Jan 25, 2018 at 8:38 PM, Daniel Collins <dancollin...@gmail.com> 
>>>> wrote:
>>>> Hello all,
>>>> 
>>>> So, first time posting here. I’ve been bothered for a while about the lack 
>>>> of the ability to chain futures in python, such that the next future will 
>>>> execute upon the first’s completion.  So I submitted a pr to do this.  
>>>> This would add the .then(self, fn) method to concurrent.futures.Future.  
>>>> Thoughts?
>>>> 
>>>> -dancollins34
>>>> 
>>>> Github PR #5335
>>>> bugs.python.org issue #32672
>>>> 
>>>> _______________________________________________
>>>> Python-ideas mailing list
>>>> Python-ideas@python.org
>>>> https://mail.python.org/mailman/listinfo/python-ideas
>>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>> 
>>> 
>>> 
>>> 
>>> -- 
>>> --Guido van Rossum (python.org/~guido)
> 
> 
> 
> -- 
> --Guido van Rossum (python.org/~guido)
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to