Skip to content

concurrent.interpreters Queue truncates fractional timeouts with int() (and accepts negative fractional timeouts) #160949

Closed as duplicate

Description

@arpittkhandelwal

Bug report

Bug description

The cross-interpreter Queue returned by
concurrent.interpreters.create_queue() documents queue.Queue semantics
for its put()/get() timeouts — the docs say that if timeout is a
positive number "it blocks at most timeout seconds"
(Doc/library/concurrent.interpreters.rst).
However, both methods convert the timeout with int(timeout) before
computing the deadline (Lib/concurrent/interpreters/_queues.py), which
truncates fractional timeouts and defeats the negative-timeout check:

import time
from concurrent import interpreters

q = interpreters.create_queue()

def timed(fn, label):
    start = time.monotonic()
    try:
        fn()
    except Exception as e:
        print(f"{label}: raised {type(e).__name__} "
              f"after {time.monotonic() - start:.2f}s")
    else:
        print(f"{label}: returned after {time.monotonic() - start:.2f}s")

timed(lambda: q.get(timeout=0.5),  "get(timeout=0.5)")
timed(lambda: q.get(timeout=1.9),  "get(timeout=1.9)")
timed(lambda: q.get(timeout=-0.5), "get(timeout=-0.5)")

Output on 3.16.0a1+ (main @ 83fe630):

get(timeout=0.5):  raised QueueEmpty after 0.00s   # expected: ~0.50s
get(timeout=1.9):  raised QueueEmpty after 1.01s   # expected: ~1.90s
get(timeout=-0.5): raised QueueEmpty after 0.00s   # expected: ValueError

put() on a full queue behaves the same way. For comparison,
queue.Queue.get(timeout=0.5) waits the full 0.50s and
queue.Queue.get(timeout=-0.5) raises
ValueError: 'timeout' must be a non-negative number immediately.

The truncation also explains why the existing tests did not catch this:
they use timeout=0.1, which truncates to 0 and still raises, just
0.1s too early.

Two knock-on effects of the int() conversion: timeout='1' is silently
accepted (stdlib raises TypeError from the < 0 comparison), and
timeout=float('inf') / float('nan') leak int()'s
OverflowError / ValueError with messages about integer conversion
rather than anything timeout-related.

Expected behaviour

Fractional timeouts are honoured like queue.Queue: the call blocks for
approximately the requested duration; any negative timeout (including
fractional ones such as -0.5) raises ValueError before waiting;
timeout=0 remains a non-blocking poll.

I have a fix and regression tests ready and will open a PR.

CPython versions tested on

CPython main (3.16.0a1+dev, 83fe630), built locally on Linux x86-64.

CPython versions tested on:

3.16

Operating systems tested on:

No response

Linked PRs

Activity

  1. added a commit that references this issue on Oct 30, 2026
  2. aisk commented on Oct 30, 2026

    @aisk
    Member

    Thank you for the report, but this is already an existing issue of the same problem: #153005, the int() truncation part is still under discussion there, so please follow up on that issue. You may also want to link your PR to that issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions