I opened a bpo issue to expand upon the public API for cf.Future:
https://bugs.python.org/issue39645. Any feedback would be greatly
appreciated. (:

On Sun, Feb 16, 2020 at 12:22 AM Guido van Rossum <gu...@python.org> wrote:

>
>
> On Sat, Feb 15, 2020 at 21:00 Kyle Stanley <aeros...@gmail.com> wrote:
>
>> > I've never felt the need for either of these myself, nor have I
>> observed it in others I worked with. In general I feel the difference
>> between processes and threads is so large that I can't believe a realistic
>> application would work with either.
>>
>> Also, ThreadPoolExecutor and ProcessPoolExecutor both have their specific
>> purposes in concurrent.futures: TPE for IO-bound parallelism, and PPE for
>> CPU-bound parallelism, what niche would the proposed SerialExecutor fall
>> under? Fake/dummy parallelism? If so, I personally don't see that as being
>> worth the cost of adding it and then maintaining it in the standard
>> library. But, that's not to say that it wouldn't have a place on PyPI.
>>
>> > (Then again I've never had much use for ProcessExecutor period.)
>>
>> I've also made use of TPE far more times than PPE, but I've definitely
>> seen several interesting and useful real-world applications of PPE.
>> Particularly with image processing. I can also imagine it also being quite
>> useful for scientific computing, although I've not personally used it for
>> that purpose.
>>
>> > IOW I'm rather lukewarm about this -- even if you (Jonathan) have found
>> use for it, I'm not sure how many other people would use it, so I doubt
>> it's worth adding it to the stdlib. (The only thing the stdlib might grow
>> could be a public API that makes implementing this feasible without
>> overriding private methods.)
>>
>> Expanding a bit upon the public API for the cf.Future class would likely
>> allow something like this to be possible without accessing any private
>> members. In particular, I believe there would have to be an public means of
>> accessing the state of the future without having to go through the
>> condition (currently, this can only be done with ``future._state``), and
>> accessing a constant for each of the possible states: PENDING. RUNNING,
>> CANCELLED, CANCELLED_AND_NOTIFIED, and FINISHED.
>>
>> Since that would actually be quite useful for debugging purposes (I had
>> to access ``future._state`` several times while testing the new
>> *cancel_futures*), I'd be willing to work on implementing something like
>> this.
>>
>
> Excellent!
>
>
>>
>> On Sat, Feb 15, 2020 at 10:16 PM Guido van Rossum <gu...@python.org>
>> wrote:
>>
>>> Having tried my hand at a simpler version for about 15 minutes, I see
>>> the reason for the fiddly subclass of Future -- it seems over-engineered
>>> because concurrent.future is complicated.
>>>
>>> I've never felt the need for either of these myself, nor have I observed
>>> it in others I worked with. In general I feel the difference between
>>> processes and threads is so large that I can't believe a realistic
>>> application would work with either. (Then again I've never had much use for
>>> ProcessExecutor period.)
>>>
>>> The "Serial" variants somehow remind me of the "dummy_thread.py" module
>>> we had in Python 2. It was removed in Python 3, mostly because we ran out
>>> of cases where real threads weren't an option.
>>>
>>> IOW I'm rather lukewarm about this -- even if you (Jonathan) have found
>>> use for it, I'm not sure how many other people would use it, so I doubt
>>> it's worth adding it to the stdlib. (The only thing the stdlib might grow
>>> could be a public API that makes implementing this feasible without
>>> overriding private methods.)
>>>
>>> On Sat, Feb 15, 2020 at 3:16 PM Jonathan Crall <erote...@gmail.com>
>>> wrote:
>>>
>>>> This implementation is a proof-of-concept that I've been using for
>>>> awhile
>>>> <https://gitlab.kitware.com/computer-vision/ndsampler/blob/master/ndsampler/util_futures.py>.
>>>> Its certain that any version that made it into the stdlib would have to be
>>>> more carefully designed than the implementation I threw together. However,
>>>> my implementation demonstrates the concept and there are reasons for the
>>>> choices I made.
>>>>
>>>> First, the choice to create a SerialFuture object that inherits from
>>>> the base Future was because I only wanted a process to run if the
>>>> SerialFuture.result method was called. The most obvious way to do that was
>>>> to overload the `result` method to execute the function when called.
>>>> Perhaps there is a better way, but in an effort to KISS I just went with
>>>> the <100 line version that seemed to work well enough.
>>>>
>>>> The `set_result` is overloaded because in Python 3.8, the base
>>>> Future.set_result function asserts that the _state is not FINISHED when it
>>>> is called. In my proof-of-concept implementation I had to set state of the
>>>> SerialFuture._state to FINISHED in order for `as_completed` to yield it.
>>>> Again, there may be a better way to do this, but I don't claim to know what
>>>> that is yet.
>>>>
>>>> I was thinking that a factory function might be a good idea, but if I
>>>> was designing the system I would have put that in the abstract Executor
>>>> class. Maybe something like
>>>>
>>>>
>>>> ```
>>>> @classmethod
>>>> def create(cls, mode, max_workers=0):
>>>>     """ Create an instance of a serial, thread, or process-based
>>>> executor """
>>>>     from concurrent import futures
>>>>     if mode == 'serial' or max_workers == 0:
>>>>         return futures.SerialExecutor()
>>>>     elif mode == 'thread':
>>>>         return futures.ThreadPoolExecutor(max_workers=max_workers)
>>>>     elif mode == 'process':
>>>>         return futures.ProcessPoolExecutor(max_workers=max_workers)
>>>>     else:
>>>>         raise KeyError(mode)
>>>> ```
>>>>
>>>> I do think that it would improve the standard lib to have something
>>>> like this --- again perhaps not this exact version (it does seem a bit
>>>> weird to give this method to an abstract class), but some common API that
>>>> makes it easy for the user to swap between the backend Executor
>>>> implementation. Even though the implementation is "trivial", lots of things
>>>> in the standard lib are, but they the reduce boilerplate that developers
>>>> would otherwise need, provide examples of good practices to new developers,
>>>> and provide a defacto way to do something that might otherwise be
>>>> implemented differently by different people, so it adds value to the
>>>> stdlib.
>>>>
>>>> That being said, while I will advocate for the inclusion of such a
>>>> factory method or wrapper class, it would only be a minor annoyance to not
>>>> have it. On the other hand I think a SerialExecutor is something that is
>>>> sorely missing from the standard library.
>>>>
>>>> On Sat, Feb 15, 2020 at 5:16 PM Andrew Barnert <abarn...@yahoo.com>
>>>> wrote:
>>>>
>>>>> > On Feb 15, 2020, at 13:36, Jonathan Crall <erote...@gmail.com>
>>>>> wrote:
>>>>> >
>>>>> > Also, there is no duck-typed class that behaves like an executor,
>>>>> but does its processing in serial. Often times a develop will want to run 
>>>>> a
>>>>> task in parallel, but depending on the environment they may want to 
>>>>> disable
>>>>> threading or process execution. To address this I use a utility called a
>>>>> `SerialExecutor` which shares an API with
>>>>> ThreadPoolExecutor/ProcessPoolExecutor but executes processes sequentially
>>>>> in the same python thread:
>>>>>
>>>>> This makes sense. I think most futures-and-executors frameworks in
>>>>> other languages have a serial/synchronous/immediate/blocking executor just
>>>>> like this. (And the ones that don’t, it’s usually because they have a
>>>>> different way to specify the same functionality—e.g., in C++, you only use
>>>>> executors via the std::async function, and you can just pass a launch
>>>>> option instead of an executor to run synchronously.)
>>>>>
>>>>> And I’ve wanted this, and even built it myself at least once—it’s a
>>>>> great way to get all of the logging in order to make things easier to
>>>>> debug, for example.
>>>>>
>>>>> However, I think you may have overengineered this.
>>>>>
>>>>> Why can’t you use the existing Future type as-is? Yes, there’s a bit
>>>>> of unnecessary overhead, but your reimplementation seems to add almost the
>>>>> same unnecessary overhead. And does it make enough difference in practice
>>>>> to be worth worrying about anyway? (It doesn’t for my uses, but maybe
>>>>> you’re are different.)
>>>>>
>>>>> Also, why are you overriding set_result to restore pre-3.8 behavior?
>>>>> The relevant change here seems to be the one where 3.8 prevents executors
>>>>> from finishing already-finished (or canceled) futures; why does your
>>>>> executor need that?
>>>>>
>>>>> Finally, why do you need a wrapper class that constructs one of the
>>>>> three types at initialization and then just delegates all methods to it?
>>>>> Why not just use a factory function that constructs and returns an 
>>>>> instance
>>>>> of one of the three types directly? And, given how trivial that factory
>>>>> function is, does it even need to be in the stdlib?
>>>>>
>>>>> I may well be missing something that makes some of these choices
>>>>> necessary or desirable. But otherwise, I think we’d be better off adding a
>>>>> SerialExecutor (that works with the existing Future type as-is) but not
>>>>> adding or changing anything else.
>>>>>
>>>>>
>>>>>
>>>>
>>>> --
>>>> -Jon
>>>> _______________________________________________
>>>> Python-ideas mailing list -- python-ideas@python.org
>>>> To unsubscribe send an email to python-ideas-le...@python.org
>>>> https://mail.python.org/mailman3/lists/python-ideas.python.org/
>>>> Message archived at
>>>> https://mail.python.org/archives/list/python-ideas@python.org/message/AG3AXJFU4R2CU6JPWCQ2BYHUPH75MKUM/
>>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>>
>>>
>>>
>>> --
>>> --Guido van Rossum (python.org/~guido)
>>> *Pronouns: he/him **(why is my pronoun here?)*
>>> <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
>>> _______________________________________________
>>> Python-ideas mailing list -- python-ideas@python.org
>>> To unsubscribe send an email to python-ideas-le...@python.org
>>> https://mail.python.org/mailman3/lists/python-ideas.python.org/
>>>
>> Message archived at
>>> https://mail.python.org/archives/list/python-ideas@python.org/message/ICJKHZ4BPIUMOPIT2TDTBIW2EH4CPNCP/
>>
>>
>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>
>> --
> --Guido (mobile)
>
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/MDXR7VESLYDOIWA7KWXDWWCVNNN7BMCD/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to