On 2011-01-09 07:04:49 -0800, exar...@twistedmatrix.com said:

Don't say it if it's not true. Deferreds aren't tied to a reactor, and Marrow doesn't appear to have anything called "deferred". So this parallel to Twisted's Deferred is misleading and confusing.

It was merely a comparison to the "you schedule something, attach some callbacks to it, and when it's finished your callbacks get executed" feature. I did not mention Twisted; also:

:: defer - postpone: hold back to a later time; "let's postpone the exam"

:: deferred - postponed: put off until a later time; "surgery has been postponed"

Futures are very similar to deferreds with the one difference you mention: future instances are created by the executor/reactor and are (possibly) the internal representation instead of Twisted treating the Deferred as the executor in terms of registering calls. In most other ways, they share the same goals, and similar methods, even.

Marrow's "deferred calls" code is buried in marrow.io, with IOStreams accepting callbacks as part of the standard read/write calls and registering these internally. IOStream then performs read/writes across the raw sockets utilizing callbacks from the IOLoop reactor. When an IOStream meets its criteria (e.g. written all of the requested data, read a number of bytes >= the requested count, or read until a marker has appeared in the stream, e.g. \r\n) IOLoop then executes the callbacks registered with it, passing the data, if any.

I will likely expand this to include additional criteria and callback hooks.

IOStream, in this way, acts more like Twisted Deferreds than Futures.

I think this effort would benefit from more thought on how exactly accessing this external library support will work. If async wsgi is limited to performing a single read asynchronously, then it hardly seems compelling.

There appears to be a misunderstanding over how futures work. Please read PEP 3148 [1] carefully. While there's not much there, here's the gist: the executor schedules the callable passed to submit. If the "worker pool" is full, the underlying pooling mechanism will delay execution of the callable until a slot is freed. Pool and slot are defined, by example only, as thread or process pools, but are not restricted to such.

(There are three relevant classes defined by concurrent.futures: Executor, ProcessPoolExecutor, and ThreadPoolExecutor. Again, as long as you implement the Executor duck-typed interface, you're good to go and compliant to PEP 3148, regardless of underlying mechanics.)

If a "slot" is available at the moment of submission, the callable has a reasonable expectation of being immediately executed. The future.result() method merely blocks awaiting completion of the already running, not yet running, or already completed future. If already completed (a la the future sent back up to to the application after yielding it) the call to result is non-blocking / immediate.

Yielding the future is simply a way of safely "blocking" (usually done by calling .result() before the future is complete), not some absolute requirement for the future itself to run. The future (and thus async socket calls et. al.) can, and should, be scheduled with the underlying async reactor in the call to submit().

        - Alice.

[1] http://www.python.org/dev/peps/pep-3148/


_______________________________________________
Web-SIG mailing list
Web-SIG@python.org
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: 
http://mail.python.org/mailman/options/web-sig/archive%40mail-archive.com

Reply via email to