[New-bugs-announce] [issue39645] Expand concurrent.futures.Future's public API

Kyle Stanley report at bugs.python.org
Sun Feb 16 02:38:05 EST 2020

New submission from Kyle Stanley <aeros167 at gmail.com>:

Based on the following python-ideas thread: https://mail.python.org/archives/list/python-ideas@python.org/thread/LMTQ2AI6A7UXEFVHRGHKWD33H24FGM6G/#ICJKHZ4BPIUMOPIT2TDTBIW2EH4CPNCP.

In the above ML thread, the author proposed adding a new cf.SerialExecutor class, which seems to be not a great fit for the standard library (based on the current state of the discussion, as of writing this). But, Guido mentioned the following:

> 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.)

Specifically, the OPs proposal should be reasonably possible to implement (either just locally for themselves or a potential PyPI package) with a few minor additions to cf.Future's public API:

1) Add a means of *publicly* accessing the future's state (future._state) without going through the internal condition's RLock.

This would allow the developer to implement their own condition or other synchronization primitive to access the state of the future. IMO, this would best be implemented as a separate ``future.state()`` and ``future.set_state()``. 

2) Add a means of *publicly* accessing the future's result (future._result) without going through the internal condition's RLock.

This would be similar to the above, but since there's already a ``future.result()`` and ``future.set_result()``, I think it would be best implemented as an optional *sync* parameter that defaults to True. When set to False, it directly accesses future._result without the condition; when set to True, it has the current behavior. 

3) Add public global constants for the different possible future states: PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, and FINISHED. 

This would be useful to serve as a template of possible future states for custom implementations. I also find that ``fut.set_state(cf.RUNNING)`` looks better than ``fut.state("running")`` from an API design perspective. 

Optional addition: To make ``fut.state()`` and ``fut.set_state()`` more useful for general purposes, it could have a single *sync* boolean parameter (feel free to bikeshed over the name), which changes whether it directly accesses future._state or does so safely through the condition. Presumably, the documentation would explicitly state that with sync=False, the future's state will not be synchronized across separate threads or processes. This would also allow it to have the same API as ``future.result()`` and ``future.set_result()``.

Also, as for my own personal motivation in expanding upon the public API for cf.Future, I've found that directly accessing the state of the future can be incredibly useful for debugging purposes. I made significant use of it while implementing the new *cancel_futures* parameter for executor.shutdown(). But, since future._state is a private member, there's no guarantee that it will continue to behave the same or that it can be relied upon in the long-term. This may not be a huge concern for quick debugging sessions, but could easily result in breakage when used in logging or unit tests.

assignee: aeros
components: Library (Lib)
messages: 362047
nosy: aeros, bquinlan, gvanrossum, pitrou
priority: normal
severity: normal
status: open
title: Expand concurrent.futures.Future's public API
type: enhancement
versions: Python 3.9

Python tracker <report at bugs.python.org>

More information about the New-bugs-announce mailing list