From: Daniele Varrazzo Date: Wed, 2 Nov 2022 11:01:42 +0000 (+0100) Subject: perf(c): take more care about the GIL around potentially blocking functions X-Git-Tag: pool-3.1.4~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ed915d2a7a8c13964e08d12faa4d53106e16d944;p=thirdparty%2Fpsycopg.git perf(c): take more care about the GIL around potentially blocking functions --- diff --git a/psycopg_c/psycopg_c/_psycopg/generators.pyx b/psycopg_c/psycopg_c/_psycopg/generators.pyx index 67bdd13f4..e389ef7a0 100644 --- a/psycopg_c/psycopg_c/_psycopg/generators.pyx +++ b/psycopg_c/psycopg_c/_psycopg/generators.pyx @@ -39,7 +39,9 @@ def connect(conninfo: str) -> PQGenConn[abc.PGconn]: pgconn=conn ) - poll_status = libpq.PQconnectPoll(pgconn_ptr) + with nogil: + poll_status = libpq.PQconnectPoll(pgconn_ptr) + if poll_status == libpq.PGRES_POLLING_OK: break elif poll_status == libpq.PGRES_POLLING_READING: @@ -142,7 +144,6 @@ def fetch_many(pq.PGconn pgconn) -> PQGen[List[PGresult]]: if status == libpq.PGRES_PIPELINE_SYNC: # PIPELINE_SYNC is not followed by a NULL, but we return it alone # similarly to other result sets. - assert len(results) == 1, results break return results @@ -158,10 +159,12 @@ def fetch(pq.PGconn pgconn) -> PQGen[Optional[PGresult]]: Return a result from the database (whether success or error). """ cdef libpq.PGconn *pgconn_ptr = pgconn._pgconn_ptr - cdef int cires, ibres = 0 + cdef int cires, ibres cdef libpq.PGresult *pgres - if libpq.PQisBusy(pgconn_ptr): + with nogil: + ibres = libpq.PQisBusy(pgconn_ptr) + if ibres: yield WAIT_R while True: with nogil: @@ -178,7 +181,8 @@ def fetch(pq.PGconn pgconn) -> PQGen[Optional[PGresult]]: _consume_notifies(pgconn) - pgres = libpq.PQgetResult(pgconn_ptr) + with nogil: + pgres = libpq.PQgetResult(pgconn_ptr) if pgres is NULL: return None return pq.PGresult._from_ptr(pgres) @@ -214,8 +218,13 @@ def pipeline_communicate( _consume_notifies(pgconn) res: List[PGresult] = [] - while not libpq.PQisBusy(pgconn_ptr): - pgres = libpq.PQgetResult(pgconn_ptr) + while True: + with nogil: + ibres = libpq.PQisBusy(pgconn_ptr) + if ibres: + break + pgres = libpq.PQgetResult(pgconn_ptr) + if pgres is NULL: if not res: break @@ -225,13 +234,11 @@ def pipeline_communicate( status = libpq.PQresultStatus(pgres) r = pq.PGresult._from_ptr(pgres) if status == libpq.PGRES_PIPELINE_SYNC: - assert not res results.append([r]) break else: res.append(r) - if ready & READY_W: pgconn.flush() if not commands: diff --git a/psycopg_c/psycopg_c/pq/libpq.pxd b/psycopg_c/psycopg_c/pq/libpq.pxd index 2f69e2fd1..5e05e40a8 100644 --- a/psycopg_c/psycopg_c/pq/libpq.pxd +++ b/psycopg_c/psycopg_c/pq/libpq.pxd @@ -106,7 +106,7 @@ cdef extern from "libpq-fe.h": # 33.1. Database Connection Control Functions PGconn *PQconnectdb(const char *conninfo) PGconn *PQconnectStart(const char *conninfo) - PostgresPollingStatusType PQconnectPoll(PGconn *conn) + PostgresPollingStatusType PQconnectPoll(PGconn *conn) nogil PQconninfoOption *PQconndefaults() PQconninfoOption *PQconninfo(PGconn *conn) PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg) @@ -131,7 +131,7 @@ cdef extern from "libpq-fe.h": int PQprotocolVersion(const PGconn *conn) int PQserverVersion(const PGconn *conn) char *PQerrorMessage(const PGconn *conn) - int PQsocket(const PGconn *conn) + int PQsocket(const PGconn *conn) nogil int PQbackendPID(const PGconn *conn) int PQconnectionNeedsPassword(const PGconn *conn) int PQconnectionUsedPassword(const PGconn *conn) @@ -160,14 +160,14 @@ cdef extern from "libpq-fe.h": const int *paramLengths, const int *paramFormats, int resultFormat) nogil - PGresult *PQdescribePrepared(PGconn *conn, const char *stmtName) - PGresult *PQdescribePortal(PGconn *conn, const char *portalName) - ExecStatusType PQresultStatus(const PGresult *res) + PGresult *PQdescribePrepared(PGconn *conn, const char *stmtName) nogil + PGresult *PQdescribePortal(PGconn *conn, const char *portalName) nogil + ExecStatusType PQresultStatus(const PGresult *res) nogil # PQresStatus: not needed, we have pretty enums - char *PQresultErrorMessage(const PGresult *res) + char *PQresultErrorMessage(const PGresult *res) nogil # TODO: PQresultVerboseErrorMessage - char *PQresultErrorField(const PGresult *res, int fieldcode) - void PQclear(PGresult *res) + char *PQresultErrorField(const PGresult *res, int fieldcode) nogil + void PQclear(PGresult *res) nogil # 33.3.2. Retrieving Query Result Information int PQntuples(const PGresult *res) @@ -232,14 +232,14 @@ cdef extern from "libpq-fe.h": const int *paramLengths, const int *paramFormats, int resultFormat) nogil - int PQsendDescribePrepared(PGconn *conn, const char *stmtName) - int PQsendDescribePortal(PGconn *conn, const char *portalName) - PGresult *PQgetResult(PGconn *conn) + int PQsendDescribePrepared(PGconn *conn, const char *stmtName) nogil + int PQsendDescribePortal(PGconn *conn, const char *portalName) nogil + PGresult *PQgetResult(PGconn *conn) nogil int PQconsumeInput(PGconn *conn) nogil int PQisBusy(PGconn *conn) nogil - int PQsetnonblocking(PGconn *conn, int arg) + int PQsetnonblocking(PGconn *conn, int arg) nogil int PQisnonblocking(const PGconn *conn) - int PQflush(PGconn *conn) + int PQflush(PGconn *conn) nogil # 33.5. Retrieving Query Results Row-by-Row int PQsetSingleRowMode(PGconn *conn)