Five functions in itertools can be substantially slowed when their input iterables generate data with lag. This might occur when the generator yields data being streamed from the internet, disk, or a multithreaded or multiprocessing workflow.
The most substantial slowdowns are in permutations, combinations, combinations_with_replacement, and product. These block the flow of execution until their input iterable(s) have completely finished being converted to a tuple. Example:
import time
import itertools
import nonblocking_itertools
def laggy_generator(iterable):
for i in iterable:
time.sleep(1)
yield i
print("Testing itertools.combinations")
start = time.time()
data = laggy_generator(range(4))
for combo in itertools.combinations(data, 2):
print("Seconds from start:", int(time.time() - start), "Combination:", combo)
print("Testing nonblocking_itertools.combinations")
start = time.time()
data = laggy_generator(range(4))
for combo in nonblocking_itertools.combinations(data, 2):
print("Seconds from start:", time.time() - start, "Combination:", combo)
Output:
Testing itertools.combinations
Seconds from start: 4 Combination: (0, 1)
Seconds from start: 4 Combination: (0, 2)
Seconds from start: 4 Combination: (0, 3)
Seconds from start: 4 Combination: (1, 2)
Seconds from start: 4 Combination: (1, 3)
Seconds from start: 4 Combination: (2, 3)
Testing nonblocking_itertools.combinations
Seconds from start: 2 Combination: (0, 1)
Seconds from start: 3 Combination: (0, 2)
Seconds from start: 3 Combination: (1, 2)
Seconds from start: 4 Combination: (0, 3)
Seconds from start: 4 Combination: (1, 3)
Seconds from start: 4 Combination: (2, 3)
Notice that all results from itertools.combinations were printed after 4 seconds, while the results from nonblocking_itertools.combinations were printed as soon as it was possible to yield them, after 2 or 3 seconds. Note that nonblocking_itertools does not generally return results in the same order as the equivalent itertools methods.
The other improvement in nonblocking_itertools is with the chain method, for when iterables have some parallelizeable processing that is initiated only during iteration. The itertools.chain method only starts iterating through later iterables when the first is exhausted. That means it misses the opportunity to kick off parallel processing in the later iterables. By contrast, nonblocking_itertools initiates immediate and simultaneous multithreaded iteration through iterables to take advantage of opportunities for parallelization. Its output is identical to itertools.chain.
Example:
import time
import itertools
import nonblocking_itertools
def laggy_generator(iterable):
for i in iterable:
time.sleep(1)
yield i
print("Testing itertools.chain")
start = time.time()
data1 = laggy_generator(range(2))
data2 = laggy_generator(range(2, 4))
for element in itertools.chain(data1, data2):
print("Seconds from start:", int(time.time() - start), "Element:", element)
print("Testing nonblocking_itertools.chain")
start = time.time()
data1 = laggy_generator(range(2))
data2 = laggy_generator(range(2, 4))
for element in nonblocking_itertools.chain(data1, data2):
print("Seconds from start:", int(time.time() - start), "Element:", element)
Output:
Testing itertools.chain
Seconds from start: 1 Element: 0
Seconds from start: 2 Element: 1
Seconds from start: 3 Element: 2
Seconds from start: 4 Element: 3
Testing nonblocking_itertools.chain
Seconds from start: 1 Element: 0
Seconds from start: 2 Element: 1
Seconds from start: 2 Element: 2
Seconds from start: 2 Element: 3
Notice that nonblocking_itertools.chain finishes after 2 seconds, while itertools.chain takes 4 seconds to finish.
Metadata
Release files for nonblocking-itertools 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| nonblocking-itertools-0.1.2.tar.gz | 3.2 kB | Without provenance | Details for nonblocking-itertools-0.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| nonblocking_itertools-0.1.2-py3-none-any.whl | Python 3 | none | any | Details for nonblocking_itertools-0.1.2-py3-none-any.whl |
Total release size: 6.2 kB
Release files / nonblocking-itertools-0.1.2.tar.gz
| Download URL | nonblocking-itertools-0.1.2.tar.gz |
|---|---|
| Size | 3.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9cd8a3bf3504da217fc0b73a3c36827f017d832eb266d9e8ece6eaa001fa2d86
|
|
BLAKE2b-256 checksum How to use checksums |
7ddc4963e3cd1c1e1323bdeb673acff21681b5167fbdb9db6242ea1e393b152a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.1.1 CPython/3.12.3
|
Release files / nonblocking_itertools-0.1.2-py3-none-any.whl
| Download URL | nonblocking_itertools-0.1.2-py3-none-any.whl |
|---|---|
| Size | 3.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d2cf8b472aeebb3b657a8849a2a5aa2b715678e2ac27a5578c9e46646deb33be
|
|
BLAKE2b-256 checksum How to use checksums |
f77e1ba13e0637033529caa5753470a59e7d5fe45216975584bd908594101852
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.1.1 CPython/3.12.3
|
Security for nonblocking-itertools 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.