
Introduction
************

Traditional methods of threads and synchronous sockets have some
drawbacks, especially with Python due to global interpreter lock
(GIL). This approach is not suited for large number of concurrent
connections, known as C10K problem. In addition, threads in Python
have both memory and time overheads, especially on multi-core systems
due to context switches; see Inside the Python GIL.

Unlike with other frameworks for asynchronous programming, using
asyncoro is very similar to the thread based programming so there is
almost no learning curve - existing thread implementations can be
converted to asyncoro almost mechanically (although it cannot be
automated). In fact, it is easier to use asyncoro than threads, as
locking is not required with asyncoro. While not required to program
with asyncoro, Curious Course on Coroutines and Concurrency offers
details on generator functions and coroutines.

For example, a simple client program to send messages using sockets
with asyncoro is:

   import sys, socket, asyncoro

   def client(host, port, n, coro=None):
       sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
       # convert 'sock' to asynchronous socket
       sock = asyncoro.AsyncSocket(sock)
       yield sock.connect((host, port))
       data = 'client id: %d' % n
       yield sock.sendall(data)
       sock.close()

   # run 10 client coroutines
   for i in range(10):
       asyncoro.Coro(client, sys.argv[1], int(sys.argv[2]), i)

The pgrogram creates 10 coroutines; each coroutine process converts
socket to asynchronous socket with "AsyncSocket", connects to server
and sends a message. In the coroutines, socket I/O operations are
called with *yield* (with *connect* and *sendall* here). With these
statements, the I/O operation is initiated, the coroutine is suspended
and control goes to asyncoro's scheduler for scheduling other
coroutines as well as processing I/O events. When an I/O operation is
complete, the scheduler resumes the suspended coroutine with the
results of the I/O operation. During the time it takes to complete an
I/O operation, the scheduler executes other coroutines, so many
requests can be concurrently processed.

Note that the program is similar to regular Python program, except for
using *yield* and creating processes with "Coro" (instead of
"threading.Thread"). Unlike with other asynchronous frameworks, the
I/O event loop in asyncoro is transparent - asyncoro's scheduler
handles I/O events automatically. If coroutine method has "coro=None"
default argument, the coroutine constructor "Coro" will set this
"coro" argument with the Coro instance, which can be used for calling
methods in "Coro" class (e.g., "yield coro.sleep(2)" to suspend
execution for 2 seconds).

asyncoro package conists of following modules:

* "asyncoro" module provides API for coroutines and asynchronous
  network programming. It includes following classes:

  * "Coro" to create coroutines, which are counterpart to threads in
    regular (synchronous) programs. Programming with coroutines is
    very similar to programming with threads, except for a few
    differences. Coroutines also support message passing for local or
    remote coroutines to exchange information.

  * "Lock", "RLock", "Event", "Semaphore", "Condition" primitives
    provide asynchronous API similar to counterparts in threading
    module. Blokcing operations in these primitives should be used
    with *yield*.

  * "AsyncSocket" should be used to convert regular (synchronous)
    socket to asynchronous socket, as done in the example above.
    Blocking operations, such as *connect*, *send*, *recv* etc. should
    be used with *yield*.

  * "Channel" provides broadcasting (one-to-many, subscription
    based) API for message passing.

* "disasyncoro" module extends "AsynCoro" and "Coro", "Channel" etc.
  so the API works for remote coroutines, channels etc. In addition,
  it provides "Location" used to refer to resource location and "RCI"
  to execute (predefined) coroutines.

* "discoro" module provides "Computation" to package computation
  fragments (code) and data to be scheduled for executing at remote
  server processes with Scheduler. The client program can then
  schedule (remote) coroutines to be executed. These coroutines and
  client can use message passing to exchange data. The remote servers
  should be started with "discoronode.py" program.

* "asyncfile" module provides "AsyncFile" and "AsyncPipe" for
  converting files and pipes to asynchronous API. Blocking operations
  on these should be used with *yield*, as with sockets.

asyncoro has been tested with Python versions 2.7 and 3.2 under Linux,
OS X and Windows. Under Windows asyncoro uses IOCP only if Python for
Windows Extensions (pywin32) is installed. pywin32 works with Windows
32-bit and 64-bit.
