Call PQisBusy() before PQconsumeInput() on fetching results. If not
busy, don't call PQconsumeInput() at all but just go to fetching results
and notifications.
This is especially useful in single-row mode because most of the times
the libpq can produce several results after a single network fetch.
Previously we were calling PQconsumeInput() also when results were
already on the client and there was nothing new to read, which forced
the libpq to run a select() to tell apart a lack of data from an EOF,
see `the grumble`_, and caused the overhead reported in #286.
Close #286.
.. _the grumble: https://github.com/postgres/postgres/blob/
ed57cac84d1c5642737dab1e4c4b8cb4f0c4305f/src/interfaces/libpq/fe-misc.c#L681
- Drop support for Python 3.6.
+Psycopg 3.0.13 (unreleased)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Fix `Cursor.stream()` slowness (:ticket:`#286`).
+
+
Current release
---------------
Return a result from the database (whether success or error).
"""
- while 1:
- pgconn.consume_input()
- if not pgconn.is_busy():
- break
+ if pgconn.is_busy():
yield Wait.R
+ while True:
+ pgconn.consume_input()
+ if not pgconn.is_busy():
+ break
+ yield Wait.R
# Consume notifies
- while 1:
+ while True:
n = pgconn.notifies()
if not n:
break
cdef object notify_handler = pgconn.notify_handler
cdef libpq.PGresult *pgres
- while 1:
- with nogil:
- cires = libpq.PQconsumeInput(pgconn_ptr)
- if cires == 1:
- ibres = libpq.PQisBusy(pgconn_ptr)
-
- if 1 != cires:
- raise e.OperationalError(
- f"consuming input failed: {error_message(pgconn)}")
- if not ibres:
- break
+ if libpq.PQisBusy(pgconn_ptr):
yield WAIT_R
+ while 1:
+ with nogil:
+ cires = libpq.PQconsumeInput(pgconn_ptr)
+ if cires == 1:
+ ibres = libpq.PQisBusy(pgconn_ptr)
+
+ if 1 != cires:
+ raise e.OperationalError(
+ f"consuming input failed: {error_message(pgconn)}")
+ if not ibres:
+ break
+ yield WAIT_R
# Consume notifies
if notify_handler is not None: