python / python/cpython

concurrent.interpreters.Queue.get()/put() mishandle the timeout argument

Offen
#153,005 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

stdlib topic-subinterpreters type-bug
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
35.9k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

concurrent.interpreters.Queue.get() and Queue.put() mishandle their
timeout argument in three related ways.

  1. The value is converted with int(timeout), which truncates a floating-point
    timeout to whole seconds. A timeout in the interval [0, 1) becomes a
    non-blocking call, and e.g. timeout=1.9 waits for only about one second.
    queue.Queue, which this queue is meant to be compatible with, accepts a
    floating-point number of seconds.

  2. Because of the same int() conversion, a small negative float such as
    timeout=-0.5 is truncated to 0 and passes the timeout < 0 check
    instead of raising ValueError.

  3. The deadline is computed with time.time() (the wall clock), while
    queue.Queue uses time.monotonic(). The timeout can therefore over- or
    under-wait if the system clock is adjusted (NTP step, manual change) during
    the call.

Reproducer (3.14.5)

import time
from concurrent.interpreters import create_queue

q = create_queue(maxsize=1)
q.put(b"x")                      # fill it
start = time.perf_counter()
try:
    q.put(b"y", timeout=0.5)     # expected: block ~0.5s, then QueueFull
except Exception as exc:
    print(type(exc).__name__, f"{(time.perf_counter() - start) * 1000:.1f} ms")
# -> QueueFull 0.0 ms   (expected ~500 ms)

q2 = create_queue()
start = time.perf_counter()
try:
    q2.get(timeout=0.9)          # expected: block ~0.9s, then QueueEmpty
except Exception as exc:
    print(type(exc).__name__, f"{(time.perf_counter() - start) * 1000:.1f} ms")
# -> QueueEmpty 0.0 ms  (expected ~900 ms)

For comparison, queue.Queue().get(timeout=0.5) blocks for about 500 ms.

The fix is to use the timeout value as given, reject a negative or NaN timeout
with ValueError, and base the deadline on time.monotonic().

Linked PRs
  • gh-153006
  • gh-154156
  • gh-155967
  • gh-156018
  • gh-156019

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit concurrent.interpreters.Queue.get() und Queue.put() und vergleiche anschließend deren Timeout-Behandlung mit queue.Queue, wie im Issue beschrieben. Bestätige das Verhalten für fraktionale, negative und NaN-Timeouts sowie bei Uhranpassungen; als erledigt gilt, dass fraktionale Wartezeiten erhalten bleiben, an den angegebenen Stellen ValueError ausgelöst wird und eine monotone Deadline verwendet wird. Sieh dir die verknüpften PRs an, bevor du beginnst, da bereits daran gearbeitet wird.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
backend
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Veraltet
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
25/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.