mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-11 03:26:37 +03:00
Fixed async documentation after cursor.poll() dropped.
This commit is contained in:
parent
a57a9976b4
commit
ac6938a26a
|
@ -6,10 +6,27 @@ More advanced topics
|
||||||
.. testsetup:: *
|
.. testsetup:: *
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import select
|
||||||
|
|
||||||
cur.execute("CREATE TABLE atable (apoint point)")
|
cur.execute("CREATE TABLE atable (apoint point)")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
|
def wait(conn):
|
||||||
|
while 1:
|
||||||
|
state = conn.poll()
|
||||||
|
if state == psycopg2.extensions.POLL_OK:
|
||||||
|
break
|
||||||
|
elif state == psycopg2.extensions.POLL_WRITE:
|
||||||
|
select.select([], [conn.fileno()], [])
|
||||||
|
elif state == psycopg2.extensions.POLL_READ:
|
||||||
|
select.select([conn.fileno()], [], [])
|
||||||
|
else:
|
||||||
|
raise psycopg2.OperationalError("poll() returned %s" % state)
|
||||||
|
|
||||||
|
aconn = psycopg2.connect(database='test', async=1)
|
||||||
|
wait(aconn)
|
||||||
|
acurs = aconn.cursor()
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
double: Subclassing; Cursor
|
double: Subclassing; Cursor
|
||||||
double: Subclassing; Connection
|
double: Subclassing; Connection
|
||||||
|
@ -255,47 +272,48 @@ Asynchronous support
|
||||||
|
|
||||||
.. versionadded:: 2.2.0
|
.. versionadded:: 2.2.0
|
||||||
|
|
||||||
Psycopg can issue asynchronous queries to a Postgresql database. An asynchronous
|
Psycopg can issue asynchronous queries to a PostgreSQL database. An asynchronous
|
||||||
communication style is estabilished passing the parameter *async*\=1 to the
|
communication style is estabilished passing the parameter *async*\=1 to the
|
||||||
`~psycopg2.connect()` function: the returned connection will work in
|
`~psycopg2.connect()` function: the returned connection will work in
|
||||||
asynchronous mode.
|
*asynchronous mode*.
|
||||||
|
|
||||||
In asynchronous mode, a Psycopg connection will rely on the caller to poll for
|
In asynchronous mode, a Psycopg connection will rely on the caller to poll the
|
||||||
the socket file descriptor ready to accept data or a query result ready to be
|
socket file descriptor, checking if it is ready to accept data or if a query
|
||||||
read from the server. The caller can use the method `~cursor.fileno()` to get
|
result has been transferred and is ready to be read on the client. The caller
|
||||||
the connection file descriptor and `~cursor.poll()` to make communication
|
can use the method `~connection.fileno()` to get the connection file
|
||||||
proceed. An application can use a loop like the one below to transfer data
|
descriptor and `~connection.poll()` to make communication proceed according to
|
||||||
between the client and the server::
|
the current connection state.
|
||||||
|
|
||||||
def wait(conn_or_cur):
|
The following is an example loop using methods `!fileno()` and `!poll()`
|
||||||
|
together with the Python |select()|_ function in order to carry on
|
||||||
|
asynchronous operations with Psycopg::
|
||||||
|
|
||||||
|
def wait(conn):
|
||||||
while 1:
|
while 1:
|
||||||
state = conn_or_cur.poll()
|
state = conn.poll()
|
||||||
if state == psycopg2.extensions.POLL_OK:
|
if state == psycopg2.extensions.POLL_OK:
|
||||||
break
|
break
|
||||||
elif state == psycopg2.extensions.POLL_WRITE:
|
elif state == psycopg2.extensions.POLL_WRITE:
|
||||||
select.select([], [conn_or_cur.fileno()], [])
|
select.select([], [conn.fileno()], [])
|
||||||
elif state == psycopg2.extensions.POLL_READ:
|
elif state == psycopg2.extensions.POLL_READ:
|
||||||
select.select([conn_or_cur.fileno()], [], [])
|
select.select([conn.fileno()], [], [])
|
||||||
else:
|
else:
|
||||||
raise psycopg2.OperationalError("poll() returned %s" % state)
|
raise psycopg2.OperationalError("poll() returned %s" % state)
|
||||||
|
|
||||||
After `!poll()` has returned `~psycopg2.extensions.POLL_OK`, the results are
|
.. |select()| replace:: `!select()`
|
||||||
available in the cursor for regular reading::
|
.. _select(): http://docs.python.org/library/select.html#select.select
|
||||||
|
|
||||||
curs.execute("SELECT * FROM foo;")
|
The above loop of course would block an entire application: in a real
|
||||||
wait(curs)
|
asynchronous framework, `!select()` would be called on many file descriptors
|
||||||
for record in curs:
|
waiting for any of them to be ready. Nonetheless the function can be used to
|
||||||
# use it...
|
connect to a PostgreSQL server only using nonblocking commands and the
|
||||||
|
connection obtained can be used to perform further nonblocking queries. After
|
||||||
|
`!poll()` has returned `~psycopg2.extensions.POLL_OK`, and thus `!wait()` has
|
||||||
|
returned, the connection can be safely used:
|
||||||
|
|
||||||
The same loop should also be used to accomplish a connection with the server:
|
>>> aconn = psycopg2.connect(database='test', async=1)
|
||||||
the connection is usable only after `connection.poll()` has returned `!POLL_OK`.
|
>>> wait(aconn)
|
||||||
The `!connection` has a `~connection.fileno()` method too, so it is possible to
|
>>> acurs = aconn.cursor()
|
||||||
use the same interface for the wait loop::
|
|
||||||
|
|
||||||
conn = psycopg2.connect(database='test', async=1)
|
|
||||||
wait(conn)
|
|
||||||
# Now you can have a cursor.
|
|
||||||
curs = conn.cursor()
|
|
||||||
|
|
||||||
Notice that there are a few other requirements to be met in order to have a
|
Notice that there are a few other requirements to be met in order to have a
|
||||||
completely non-blocking connection attempt: see the libpq documentation for
|
completely non-blocking connection attempt: see the libpq documentation for
|
||||||
|
@ -304,17 +322,29 @@ completely non-blocking connection attempt: see the libpq documentation for
|
||||||
.. |PQconnectStart| replace:: `!PQconnectStart()`
|
.. |PQconnectStart| replace:: `!PQconnectStart()`
|
||||||
.. _PQconnectStart: http://www.postgresql.org/docs/8.4/static/libpq-connect.html#AEN33199
|
.. _PQconnectStart: http://www.postgresql.org/docs/8.4/static/libpq-connect.html#AEN33199
|
||||||
|
|
||||||
|
The same loop should be also used to perform nonblocking queries: after
|
||||||
|
sending a query via `~cursor.execute()` or `~cursor.callproc()`, call
|
||||||
|
`!poll()` on the connection available from `cursor.connection` until it
|
||||||
|
returns `!POLL_OK`, at which pont the query has been completely sent to the
|
||||||
|
server and, if it produced data, the results have been transferred to the
|
||||||
|
client and available using the regular cursor methods:
|
||||||
|
|
||||||
|
>>> acurs.execute("SELECT pg_sleep(5); SELECT 42;")
|
||||||
|
>>> wait(acurs.connection)
|
||||||
|
>>> acurs.fetchone()[0]
|
||||||
|
42
|
||||||
|
|
||||||
When an asynchronous query is being executed, `connection.executing()` returns
|
When an asynchronous query is being executed, `connection.executing()` returns
|
||||||
`True`. Two cursors can't execute concurrent queries on the same asynchronous
|
`True`. Two cursors can't execute concurrent queries on the same asynchronous
|
||||||
connection.
|
connection.
|
||||||
|
|
||||||
There are several limitations in using asynchronous connections: the connection
|
There are several limitations in using asynchronous connections: the
|
||||||
is always in :ref:`autocommit <autocommit>` mode and it is not possible to
|
connection is always in :ref:`autocommit <autocommit>` mode and it is not
|
||||||
change it using `~connection.set_isolation_level()`. So transaction are not
|
possible to change it using `~connection.set_isolation_level()`. So a
|
||||||
started at each query and is not possible to use methods `~connection.commit()`
|
transaction is not implicitly started at the first query and is not possible
|
||||||
and `~connection.rollback()`: you can manually control transactions using
|
to use methods `~connection.commit()` and `~connection.rollback()`: you can
|
||||||
`~cursor.execute()` to send commands :sql:`BEGIN`, :sql:`COMMIT` and
|
manually control transactions using `~cursor.execute()` to send database
|
||||||
:sql:`ROLLBACK`.
|
commands such as :sql:`BEGIN`, :sql:`COMMIT` and :sql:`ROLLBACK`.
|
||||||
|
|
||||||
With asynchronous connections it is also not possible to use
|
With asynchronous connections it is also not possible to use
|
||||||
`~connection.set_client_encoding()`, `~cursor.executemany()`, :ref:`large
|
`~connection.set_client_encoding()`, `~cursor.executemany()`, :ref:`large
|
||||||
|
@ -328,6 +358,7 @@ this will be probably implemented in a future release.
|
||||||
.. testcode::
|
.. testcode::
|
||||||
:hide:
|
:hide:
|
||||||
|
|
||||||
|
aconn.close()
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
cur.execute("DROP TABLE atable")
|
cur.execute("DROP TABLE atable")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
|
@ -329,19 +329,22 @@ The ``connection`` class
|
||||||
|
|
||||||
.. method:: poll()
|
.. method:: poll()
|
||||||
|
|
||||||
Used during an asynchronous connection attempt, make communication
|
Used during an asynchronous connection attempt, or when a cursor is
|
||||||
|
executing a query on an asynchronous connection, make communication
|
||||||
proceed if it wouldn't block.
|
proceed if it wouldn't block.
|
||||||
|
|
||||||
Return one of the constants defined in :ref:`poll-constants`. If it
|
Return one of the constants defined in :ref:`poll-constants`. If it
|
||||||
returns `~psycopg2.extensions.POLL_OK` the connection has been
|
returns `~psycopg2.extensions.POLL_OK` then the connection has been
|
||||||
estabilished. Otherwise wait until the file descriptor is ready as
|
estabilished or the query results are available on the client.
|
||||||
explained in :ref:`async-support`.
|
Otherwise wait until the file descriptor returned by
|
||||||
|
`~connection.fileno()` is ready to read or to write, as explained in
|
||||||
|
:ref:`async-support`.
|
||||||
|
|
||||||
|
|
||||||
.. method:: fileno()
|
.. method:: fileno()
|
||||||
|
|
||||||
Return the file descriptor associated with the connection to read the
|
Return the file descriptor underlying the connection: useful to read
|
||||||
status during asynchronous communication.
|
its status during asynchronous communication.
|
||||||
|
|
||||||
|
|
||||||
.. method:: executing()
|
.. method:: executing()
|
||||||
|
|
|
@ -390,34 +390,6 @@ The ``cursor`` class
|
||||||
.. _tzinfo: http://docs.python.org/library/datetime.html#tzinfo-objects
|
.. _tzinfo: http://docs.python.org/library/datetime.html#tzinfo-objects
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. rubric:: Methods related to asynchronous support.
|
|
||||||
|
|
||||||
.. extension::
|
|
||||||
|
|
||||||
:ref:`Asynchronous support <async-support>` is a Psycopg extension to
|
|
||||||
the |DBAPI|.
|
|
||||||
|
|
||||||
|
|
||||||
.. method:: poll()
|
|
||||||
|
|
||||||
Used during asynchronous queries, make asynchronous communication
|
|
||||||
proceed if it wouldn't block.
|
|
||||||
|
|
||||||
Return `~psycopg2.extensions.POLL_OK` if the query has been fully
|
|
||||||
processed, `~psycopg2.extensions.POLL_READ` if the query has been sent
|
|
||||||
and the application should be waiting for the result to arrive or
|
|
||||||
`~psycopg2.extensions.POLL_WRITE` is the query is still being sent.
|
|
||||||
|
|
||||||
|
|
||||||
.. method:: fileno()
|
|
||||||
|
|
||||||
Return the file descriptor associated with the current connection to
|
|
||||||
make possible to use a cursor in a context where a file object would
|
|
||||||
be expected (like in a `select()` call).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. rubric:: COPY-related methods
|
.. rubric:: COPY-related methods
|
||||||
|
|
||||||
.. extension::
|
.. extension::
|
||||||
|
|
|
@ -455,25 +455,29 @@ Poll constants
|
||||||
|
|
||||||
.. versionadded:: 2.2.0
|
.. versionadded:: 2.2.0
|
||||||
|
|
||||||
These values can be returned by `connection.poll()` and `cursor.poll()` during
|
These values can be returned by `connection.poll()` during asynchronous
|
||||||
asynchronous communication. See :ref:`async-support`.
|
connection and communication. See :ref:`async-support`.
|
||||||
|
|
||||||
.. data:: POLL_OK
|
.. data:: POLL_OK
|
||||||
|
|
||||||
The data is available (or the file descriptor is ready for writing): there
|
The data being read is available, or the file descriptor is ready for
|
||||||
is no need to block anymore.
|
writing: reading or writing will not block.
|
||||||
|
|
||||||
.. data:: POLL_READ
|
.. data:: POLL_READ
|
||||||
|
|
||||||
Upon receiving this value, the callback should wait for the connection
|
Some data is being read from the backend, but it is not available yet on
|
||||||
file descriptor to be ready *for reading*. For example::
|
the client and reading would block. Upon receiving this value, the client
|
||||||
|
should wait for the connection file descriptor to be ready *for reading*.
|
||||||
|
For example::
|
||||||
|
|
||||||
select.select([conn.fileno()], [], [])
|
select.select([conn.fileno()], [], [])
|
||||||
|
|
||||||
.. data:: POLL_WRITE
|
.. data:: POLL_WRITE
|
||||||
|
|
||||||
Upon receiving this value, the callback should wait for the connection
|
Some data is being sent to the backend but the connection file descriptor
|
||||||
file descriptor to be ready *for writing*. For example::
|
can't currently accept new data. Upon receiving this value, the client
|
||||||
|
should wait for the connection file descriptor to be ready *for writing*.
|
||||||
|
For example::
|
||||||
|
|
||||||
select.select([], [conn.fileno()], [])
|
select.select([], [conn.fileno()], [])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user