Future
Future is a container that can hold either the result of a computation or an error that occurred during that computation. When a future is created, it starts in a PENDING state. The library does not intend for this object to be created manually, except perhaps for testing purposes.
import concurrent.futures as futures f = futures.Future() assert(f._result is None) assert(f._exception is None) assert(f._state == 'PENDING')
The PENDING status indicates that a computation requested by the user has been registered in the thread pool and placed in a queue, but it has not yet been picked up by any thread for execution. Once a free thread takes the task (callback) from the queue, the future transitions to the RUNNING state. A future can only be canceled while it is in the PENDING state. Therefore, there is a window of time between the PENDING and RUNNING states during which the requested computation can be canceled.
import concurrent.futures as futures def should_cancel_pending_future(): f = futures.Future() assert(f._state == 'PENDING') assert(f.cancel()) assert(f._state == 'CANCELLED') def should_not_cancel_running_future(): f = futures.Future() f.set_running_or_notify_cancel() assert(f._state == 'RUNNING') assert(not f.cancel()) def cancel_is_idempotent(): f = futures.Future() assert(f.cancel()) assert(f.cancel()) should_cancel_pending_future() should_not_cancel_running_future() cancel_is_idempotent()
A requested operation in the thread pool can either complete with a computed value or result in an error. Regardless of the outcome, the future transitions to the FINISHED state. The result or error is then stored in the corresponding fields.
import concurrent.futures as futures def future_completed_with_result(): f = futures.Future() f.set_result('foo') assert(f._state == 'FINISHED') assert(f._result == 'foo') assert(f._exception is None) def future_completed_with_exception(): f = futures.Future() f.set_exception(NameError()) assert(f._state == 'FINISHED') assert(f._result is None) assert(isinstance(f._exception, NameError)) future_completed_with_result() future_completed_with_exception()
To retrieve the result of a computation, the result method is used. If the computation is not yet complete, this method will block the current thread (from which result was called) until the computation finishes or the wait times out.
If the computation completes successfully without errors, the result method returns the computed value.
import concurrent.futures as futures import time import threading f = futures.Future() def target(): time.sleep(1) f.set_result('foo') threading.Thread(target=target).start() assert(f.result() == 'foo')
If an exception occurred during the computation, result will raise that exception.
import concurrent.futures as futures import time import threading f = futures.Future() def target(): time.sleep(1) f.set_exception(NameError) threading.Thread(target=target).start() try: f.result() raise Exception() except NameError: assert(True)
If the method times out while waiting, a TimeoutError is raised.
import concurrent.futures as futures f = futures.Future() try: f.result(1) raise Exception() except TimeoutError: assert(f._result is None) assert(f._exception is None)
The attempt to obtain the result of a computation that was canceled will raise a CancelledError.
import concurrent.futures as futures f = futures.Future() assert(f.cancel()) try: f.result() raise Exception() except futures.CancelledError: assert(True)
Waiting strategy
In the development process, it is quite common to need to run N computations on a thread pool and wait for their completion. To achieve this, the library provides wait function. There are several waiting strategies: FIRST_COMPLETED, FIRST_EXCEPTION, ALL_COMPLETED.
Common to all waiting strategies is that if the futures passed to the wait method are already completed, the collection of the passed futures is returned regardless of the chosen strategy. It does not matter how they were completed whether with an error, a result, or if they were canceled.
import concurrent.futures as futures def test(return_when): f1, f2, f3 = futures.Future(), futures.Future(), futures.Future() f1.cancel() f1.set_running_or_notify_cancel() # required f2.set_result('foo') f3.set_exception(NameError) r = futures.wait([f1, f2, f3], return_when=return_when) assert(len(r.done) == 3) assert(len(r.not_done) == 0) for return_when in [futures.ALL_COMPLETED, futures.FIRST_EXCEPTION, futures.FIRST_COMPLETED]: test(return_when)
ALL_COMPLETED strategy
The ALL_COMPLETED strategy guarantees waiting for the completion of all the passed futures, or exiting after a timeout with a collection of the futures completed up to that moment, which may be incomplete.
import concurrent.futures as futures f = futures.Future() assert(f._result is None) assert(f._exception is None) assert(f._state == 'PENDING')
FIRST_COMPLETED
The FIRST_COMPLETED strategy guarantees the return of a collection with at least one completed future or an empty collection in case of a timeout. This strategy DOES NOT imply that the returned collection cannot contain multiple elements.
import concurrent.futures as futures def should_cancel_pending_future(): f = futures.Future() assert(f._state == 'PENDING') assert(f.cancel()) assert(f._state == 'CANCELLED') def should_not_cancel_running_future(): f = futures.Future() f.set_running_or_notify_cancel() assert(f._state == 'RUNNING') assert(not f.cancel()) def cancel_is_idempotent(): f = futures.Future() assert(f.cancel()) assert(f.cancel()) should_cancel_pending_future() should_not_cancel_running_future() cancel_is_idempotent()
FIRST_EXCEPTION
The FIRST_EXCEPTION strategy interrupts the wait if one of the computations finishes with an error. If no exceptions occur, the behavior is identical to the ALL_COMPLETED future.
import concurrent.futures as futures def future_completed_with_result(): f = futures.Future() f.set_result('foo') assert(f._state == 'FINISHED') assert(f._result == 'foo') assert(f._exception is None) def future_completed_with_exception(): f = futures.Future() f.set_exception(NameError()) assert(f._state == 'FINISHED') assert(f._result is None) assert(isinstance(f._exception, NameError)) future_completed_with_result() future_completed_with_exception()
ThreadPoolExecutor
The object is responsible for creating a thread pool. The main method for interacting with this object is the Submit method. It allows to register a computation in the thread pool. In response, a Future object is returned, which is used to monitor the computation's status and obtain the final result.
Properties
- New threads are created ONLY as needed:
- If there is at least one free thread when a computation is requested, no new thread is created
- If there are no free threads when a computation is requested, a new thread is created, provided that the maxWorkers limit has not been reached.
- If there are no free threads and the maxWorkers limit has been reached, the computation is placed in a queue and will be taken by the next available thread
- The maximum number of threads allocated for computational needs by default equals the number of logical processor cores
- Once created, a thread is not destroyed, even in case of low load
The above is the detailed content of python concurrent.futures. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Polymorphism is a core concept in Python object-oriented programming, referring to "one interface, multiple implementations", allowing for unified processing of different types of objects. 1. Polymorphism is implemented through method rewriting. Subclasses can redefine parent class methods. For example, the spoke() method of Animal class has different implementations in Dog and Cat subclasses. 2. The practical uses of polymorphism include simplifying the code structure and enhancing scalability, such as calling the draw() method uniformly in the graphical drawing program, or handling the common behavior of different characters in game development. 3. Python implementation polymorphism needs to satisfy: the parent class defines a method, and the child class overrides the method, but does not require inheritance of the same parent class. As long as the object implements the same method, this is called the "duck type". 4. Things to note include the maintenance

The "Hello,World!" program is the most basic example written in Python, which is used to demonstrate the basic syntax and verify that the development environment is configured correctly. 1. It is implemented through a line of code print("Hello,World!"), and after running, the specified text will be output on the console; 2. The running steps include installing Python, writing code with a text editor, saving as a .py file, and executing the file in the terminal; 3. Common errors include missing brackets or quotes, misuse of capital Print, not saving as .py format, and running environment errors; 4. Optional tools include local text editor terminal, online editor (such as replit.com)

AlgorithmsinPythonareessentialforefficientproblem-solvinginprogramming.Theyarestep-by-stepproceduresusedtosolvetaskslikesorting,searching,anddatamanipulation.Commontypesincludesortingalgorithmslikequicksort,searchingalgorithmslikebinarysearch,andgrap

ListslicinginPythonextractsaportionofalistusingindices.1.Itusesthesyntaxlist[start:end:step],wherestartisinclusive,endisexclusive,andstepdefinestheinterval.2.Ifstartorendareomitted,Pythondefaultstothebeginningorendofthelist.3.Commonusesincludegetting

A class method is a method defined in Python through the @classmethod decorator. Its first parameter is the class itself (cls), which is used to access or modify the class state. It can be called through a class or instance, which affects the entire class rather than a specific instance; for example, in the Person class, the show_count() method counts the number of objects created; when defining a class method, you need to use the @classmethod decorator and name the first parameter cls, such as the change_var(new_value) method to modify class variables; the class method is different from the instance method (self parameter) and static method (no automatic parameters), and is suitable for factory methods, alternative constructors, and management of class variables. Common uses include:

Python's csv module provides an easy way to read and write CSV files. 1. When reading a CSV file, you can use csv.reader() to read line by line and return each line of data as a string list; if you need to access the data through column names, you can use csv.DictReader() to map each line into a dictionary. 2. When writing to a CSV file, use csv.writer() and call writerow() or writerows() methods to write single or multiple rows of data; if you want to write dictionary data, use csv.DictWriter(), you need to define the column name first and write the header through writeheader(). 3. When handling edge cases, the module automatically handles them

Parameters are placeholders when defining a function, while arguments are specific values ??passed in when calling. 1. Position parameters need to be passed in order, and incorrect order will lead to errors in the result; 2. Keyword parameters are specified by parameter names, which can change the order and improve readability; 3. Default parameter values ??are assigned when defined to avoid duplicate code, but variable objects should be avoided as default values; 4. args and *kwargs can handle uncertain number of parameters and are suitable for general interfaces or decorators, but should be used with caution to maintain readability.

Iterators are objects that implement __iter__() and __next__() methods. The generator is a simplified version of iterators, which automatically implement these methods through the yield keyword. 1. The iterator returns an element every time he calls next() and throws a StopIteration exception when there are no more elements. 2. The generator uses function definition to generate data on demand, saving memory and supporting infinite sequences. 3. Use iterators when processing existing sets, use a generator when dynamically generating big data or lazy evaluation, such as loading line by line when reading large files. Note: Iterable objects such as lists are not iterators. They need to be recreated after the iterator reaches its end, and the generator can only traverse it once.
