Dropping concurrent.futures.Executor.map result cancels pending futures
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Python
- Star
- 77.2k
- Fork
- 35.9k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
Bug report
Bug description:
Code:
from concurrent.futures import ThreadPoolExecutor
data = [
list(range(0, 5)),
list(range(5, 10)),
]
def _f(x):
print(f"Processing {x}")
return True
print("=== 1 - No consumption from the iterator ===")
executor = ThreadPoolExecutor(max_workers=1)
for ints in data:
executor.map(_f, ints)
executor.shutdown(wait=True)
print("=== 2 - Consume all values from the iterator ===")
executor = ThreadPoolExecutor(max_workers=1)
for ints in data:
futures = executor.map(_f, ints)
results = list(futures)
executor.shutdown(wait=True)
print("=== 3 - Consume one value from the iterator ===")
executor = ThreadPoolExecutor(max_workers=1)
for ints in data:
futures = executor.map(_f, ints)
first = next(futures)
executor.shutdown(wait=True)
print("=== 4 - Dropping iterator cancels remaining futures ===")
executor = ThreadPoolExecutor(max_workers=1)
futures = executor.map(_f, range(0, 5))
first = next(futures)
del futures
executor.shutdown(wait=True)
Result:
=== 1 - No consumption from the iterator ===
Processing 0
Processing 1
Processing 2
Processing 3
Processing 4
Processing 5
Processing 6
Processing 7
Processing 8
Processing 9
=== 2 - Consume all values from the iterator ===
Processing 0
Processing 1
Processing 2
Processing 3
Processing 4
Processing 5
Processing 6
Processing 7
Processing 8
Processing 9
=== 3 - Consume one value from the iterator ===
Processing 0
Processing 1
Processing 5
Processing 6
Processing 7
Processing 8
Processing 9
=== 4 - Dropping iterator cancels remaining futures ===
Processing 0
Processing 1
The behaviour seems to be:
- If the iterator returned from
mapis never used (case 1), futures are not cancelled - If the iterator returned from
mapis exhausted (case 2), futures are not cancelled - If the iterator returned from
mapis partially consumed and then dropped (cases 3 & 4), the remaining futures are cancelled
We hit this doing a version of case 3, calling any on the iterator, which short-circuited, causing the remaining futures to not execute. This tripped us up and seems like quite a confusing behaviour that is not flagged in the docs.
It looks like this is caused by this code: https://github.com/python/cpython/blob/main/Lib/concurrent/futures/_base.py#L669-L671
Possibly related to https://github.com/python/cpython/issues/108518
CPython versions tested on:
3.12
Operating systems tested on:
Linux
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu bằng cách tái hiện bốn trường hợp trên CPython 3.12/Linux, sau đó kiểm tra Lib/concurrent/futures/_base.py ở các dòng 669-671 và issue liên quan #108518. Xác định hành vi dự kiến đối với các iterator map được tiêu thụ một phần, bổ sung kiểm thử hồi quy hoặc tài liệu khi thích hợp, và xác minh rằng các trường hợp thực thi được báo cáo được xử lý nhất quán.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- python
- Lĩnh vực
- backend
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 42/100