-
Notifications
You must be signed in to change notification settings - Fork 246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[discussion] Should functions like spawn take a coroutine object, or the classic fn+args+kwargs tuple? #122
Comments
On 11/20/16, Nathaniel J. Smith [email protected] wrote:
spawn(co) is much better. Control over the creation and manupulation
I dont think it is an important reason. Current form is also handy.
It is the awkwardness of Python.
It is the nature of such functions. Like calling threads. No better solution I think no generalization is possible for all cases. That's why we |
I like the current approach. |
OK. But, I mean... I liked the current approach too, until I started using it more and started running into some issues. Obviously it's your project and you don't owe me anything, but I admit it's a bit frustrating to write down some concrete analyses of the issues and then get two replies that brush these aside without engaging with the trade-offs. |
Sorry. Didn't mean to be curt--I'm often very scattered for time with kids and other things going on. I've been meaning to get back here. A few thoughts... I like the current approach because it is extremely minimal and simple. You provide a coroutine and curio runs it. One of my major complaints with asyncio is that it is just too complicated for me to remember how to do anything. Getting the event loop. A about a half-dozen methods all related to running things, all slightly different. I don't like it. Saying I also like the current approach because it is easy to have optional keyword arguments attached to the I must admit that the fact that coroutines don't immediately evaluate until awaited is something that takes some getting used to though. There are all sorts of crazy ways of passing them around in an unevaluated state and then doing things later. |
So, I was recently doing a bunch of coding involving Curio and threads. You're right, the calling conventions are different. Naturally this issue makes it impossible to "unsee" the difference. I'm not entirely sure I'm going to do anything about it (yet), but I see what you mean here. Need to think about it more. |
Confession: I'm still thinking about this issue. You're absolutely right, there is an inconsistency here. There are a couple of different ways of spawning work in Python (in the library). There are threads:
There is multiprocessing:
And there are executors (from concurrent.futures):
Asyncio has a
If you want keyword arguments, you'd have to partial it:
Of these, I personally like the Getting back to
I could make I'm just not sure what to do with additional keyword arguments to
Or there could simply be "reserved" keyword arguments to curio recognizes and that you'd have to avoid in called code. Anyways, I'm still thinking about this. Wondering if anyone has any renewed ideas about it here. |
Apart from consistency what exactly we will gain from this? co = cofunc(...) Infact on the contrary bringing such a convention to pco = Process(...) I remember we also had been talking about |
Coroutines and Threads/Process DO NOT share same |
Basically, it's just consistency. It's not an entirely unimportant thing in my experience, but maybe it's impossible to get right in all cases. I was just thinking that if |
It's a minor thing, but I've found myself mostly sticking to using the
context manager forms of the timeout commands anyway. I could see an
argument for making that the One Way to do it, just to simplify things a
bit.
…On Dec 27, 2016 3:57 PM, "David Beazley" ***@***.***> wrote:
Basically, it's just consistency. It's not an entirely unimportant thing
in my experience, but maybe it's impossible to get right in all cases. I
was just thinking that if spawn() changed, then you might also turn to
changing functions such as timeout_after() as well. Hmmm. Now I'm not so
sure.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#122 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAlOaC6FzUaYU2FJ8zq1KZokFbwPiZC7ks5rMaXwgaJpZM4K3eXs>
.
|
Wait... How didn't I see it? pco = Process/Thread(...) Of course it is meaningful: It is equivalent to launching Himmm... Anyway currently we don't have much api to control and As we make progress on them lets keep this issue alive.. |
As an aside, I do not hold the standard library sacred with respect to how curio might potentially interact with threads or processes. So, all experimentation is encouraged :-). |
On 12/28/16, David Beazley ***@***.***> wrote:
As an aside, I do not hold the standard library sacred with respect to how
curio might potentially interact with threads or processes.
Right.. Not holding a library/language as sacred is a good thing. ;)
|
I've continued to think about this issue for awhile. Curio has grown some new functions for launching processes, performing work, and so forth. Some consistency is order. I'm going to modifiy curio to use a common signature for "launching" work whether it be a task, a thread, a process, or whatever:
Keyword arguments, if any, are reserved for options related to Because of some backwards compatibility concerns with existing code, passing an instantiated coroutine to certain functions (spawn, run, etc.) will still work. However, documentation and examples will prefer the new approach. |
I have modified curio to fairly universally adopt an API such as:
The older API such as:
will continue to work however. Basically, you can either pass an instantiated coroutine or a callable with arguments will be executed to produce a coroutine. |
Right now,
curio.run
andcurio.spawn
take a coroutine object, i.e., the return value from calling an async function:This is fairly elegant and I'm not sure it's wrong, but I've run into a few situations where it's feeling a bit awkward, so I wanted to raise for the discussion the possibility that they should instead take an async callable + arguments:
The arguments for taking a callable:
curio.run
andcurio.spawn
, you could get a long way with beginners pretending thatawait f(...)
is a single indivisible piece of syntax, an "async call". Obviously you want to break this down eventually, butcurio.run
andcurio.spawn
force you to do it immediately.)spawn_supervised(coro)
method, which might error out if the supervisor is not running. Of course my tests have to invoke this, so get an unavoidable warning...) For consistency, it would be nice if these functions used the same calling convention ascurio.spawn
.curio.tcp_server
, or thespawn_supervised
method on a task supervisor that supports automatically restarted crashed tasks (like Erlang supervisors do). For consistency, it would be nice if these functions used the same calling convention ascurio.spawn
.The arguments against taking a callable:
Breaks compatibility, but eh, that's why this is "experimental".
It's nice to collect up the fn/args/kwargs into a single object, so as to avoid confusion between arguments-for-the-function versus arguments-for-
run
-or-spawn
. In particular, if we actually made this change, then probably the best way to do it would be to make the signature ofrun
andspawn
be:i.e., positional arguments belong to the function, but kwargs are reserved for
run
orspawn
. Or we might not even want to allow positional args at all, and just make it a bare zero-args callable:The counter-argument to this is that we already have perfectly nice and idiomatic ways in Python to bundle up fn/args/kwargs together:
And we have to use this style anyway for things like
tcp_server
, so we might as well use it everywhere.The text was updated successfully, but these errors were encountered: