mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-23 01:16:34 +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:: *
|
||||
|
||||
import re
|
||||
import select
|
||||
|
||||
cur.execute("CREATE TABLE atable (apoint point)")
|
||||
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::
|
||||
double: Subclassing; Cursor
|
||||
double: Subclassing; Connection
|
||||
|
@ -255,47 +272,48 @@ Asynchronous support
|
|||
|
||||
.. 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
|
||||
`~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
|
||||
the socket file descriptor ready to accept data or a query result ready to be
|
||||
read from the server. The caller can use the method `~cursor.fileno()` to get
|
||||
the connection file descriptor and `~cursor.poll()` to make communication
|
||||
proceed. An application can use a loop like the one below to transfer data
|
||||
between the client and the server::
|
||||
In asynchronous mode, a Psycopg connection will rely on the caller to poll the
|
||||
socket file descriptor, checking if it is ready to accept data or if a query
|
||||
result has been transferred and is ready to be read on the client. The caller
|
||||
can use the method `~connection.fileno()` to get the connection file
|
||||
descriptor and `~connection.poll()` to make communication proceed according to
|
||||
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:
|
||||
state = conn_or_cur.poll()
|
||||
state = conn.poll()
|
||||
if state == psycopg2.extensions.POLL_OK:
|
||||
break
|
||||
elif state == psycopg2.extensions.POLL_WRITE:
|
||||
select.select([], [conn_or_cur.fileno()], [])
|
||||
select.select([], [conn.fileno()], [])
|
||||
elif state == psycopg2.extensions.POLL_READ:
|
||||
select.select([conn_or_cur.fileno()], [], [])
|
||||
select.select([conn.fileno()], [], [])
|
||||
else:
|
||||
raise psycopg2.OperationalError("poll() returned %s" % state)
|
||||
|
||||
After `!poll()` has returned `~psycopg2.extensions.POLL_OK`, the results are
|
||||
available in the cursor for regular reading::
|
||||
.. |select()| replace:: `!select()`
|
||||
.. _select(): http://docs.python.org/library/select.html#select.select
|
||||
|
||||
curs.execute("SELECT * FROM foo;")
|
||||
wait(curs)
|
||||
for record in curs:
|
||||
# use it...
|
||||
The above loop of course would block an entire application: in a real
|
||||
asynchronous framework, `!select()` would be called on many file descriptors
|
||||
waiting for any of them to be ready. Nonetheless the function can be used to
|
||||
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:
|
||||
the connection is usable only after `connection.poll()` has returned `!POLL_OK`.
|
||||
The `!connection` has a `~connection.fileno()` method too, so it is possible to
|
||||
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()
|
||||
>>> aconn = psycopg2.connect(database='test', async=1)
|
||||
>>> wait(aconn)
|
||||
>>> acurs = aconn.cursor()
|
||||
|
||||
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
|
||||
|
@ -304,17 +322,29 @@ completely non-blocking connection attempt: see the libpq documentation for
|
|||
.. |PQconnectStart| replace:: `!PQconnectStart()`
|
||||
.. _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
|
||||
`True`. Two cursors can't execute concurrent queries on the same asynchronous
|
||||
connection.
|
||||
|
||||
There are several limitations in using asynchronous connections: the connection
|
||||
is always in :ref:`autocommit <autocommit>` mode and it is not possible to
|
||||
change it using `~connection.set_isolation_level()`. So transaction are not
|
||||
started at each query and is not possible to use methods `~connection.commit()`
|
||||
and `~connection.rollback()`: you can manually control transactions using
|
||||
`~cursor.execute()` to send commands :sql:`BEGIN`, :sql:`COMMIT` and
|
||||
:sql:`ROLLBACK`.
|
||||
There are several limitations in using asynchronous connections: the
|
||||
connection is always in :ref:`autocommit <autocommit>` mode and it is not
|
||||
possible to change it using `~connection.set_isolation_level()`. So a
|
||||
transaction is not implicitly started at the first query and is not possible
|
||||
to use methods `~connection.commit()` and `~connection.rollback()`: you can
|
||||
manually control transactions using `~cursor.execute()` to send database
|
||||
commands such as :sql:`BEGIN`, :sql:`COMMIT` and :sql:`ROLLBACK`.
|
||||
|
||||
With asynchronous connections it is also not possible to use
|
||||
`~connection.set_client_encoding()`, `~cursor.executemany()`, :ref:`large
|
||||
|
@ -328,6 +358,7 @@ this will be probably implemented in a future release.
|
|||
.. testcode::
|
||||
:hide:
|
||||
|
||||
aconn.close()
|
||||
conn.rollback()
|
||||
cur.execute("DROP TABLE atable")
|
||||
conn.commit()
|
||||
|
|
|
@ -329,19 +329,22 @@ The ``connection`` class
|
|||
|
||||
.. 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.
|
||||
|
||||
Return one of the constants defined in :ref:`poll-constants`. If it
|
||||
returns `~psycopg2.extensions.POLL_OK` the connection has been
|
||||
estabilished. Otherwise wait until the file descriptor is ready as
|
||||
explained in :ref:`async-support`.
|
||||
returns `~psycopg2.extensions.POLL_OK` then the connection has been
|
||||
estabilished or the query results are available on the client.
|
||||
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()
|
||||
|
||||
Return the file descriptor associated with the connection to read the
|
||||
status during asynchronous communication.
|
||||
Return the file descriptor underlying the connection: useful to read
|
||||
its status during asynchronous communication.
|
||||
|
||||
|
||||
.. method:: executing()
|
||||
|
|
|
@ -390,34 +390,6 @@ The ``cursor`` class
|
|||
.. _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
|
||||
|
||||
.. extension::
|
||||
|
|
|
@ -455,25 +455,29 @@ Poll constants
|
|||
|
||||
.. versionadded:: 2.2.0
|
||||
|
||||
These values can be returned by `connection.poll()` and `cursor.poll()` during
|
||||
asynchronous communication. See :ref:`async-support`.
|
||||
These values can be returned by `connection.poll()` during asynchronous
|
||||
connection and communication. See :ref:`async-support`.
|
||||
|
||||
.. data:: POLL_OK
|
||||
|
||||
The data is available (or the file descriptor is ready for writing): there
|
||||
is no need to block anymore.
|
||||
The data being read is available, or the file descriptor is ready for
|
||||
writing: reading or writing will not block.
|
||||
|
||||
.. data:: POLL_READ
|
||||
|
||||
Upon receiving this value, the callback should wait for the connection
|
||||
file descriptor to be ready *for reading*. For example::
|
||||
Some data is being read from the backend, but it is not available yet on
|
||||
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()], [], [])
|
||||
|
||||
.. data:: POLL_WRITE
|
||||
|
||||
Upon receiving this value, the callback should wait for the connection
|
||||
file descriptor to be ready *for writing*. For example::
|
||||
Some data is being sent to the backend but the connection file descriptor
|
||||
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()], [])
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user