Re: Issues with "twistd" in Twisted 16.4.0

2016-09-01 Thread Kevin Conway
Hi, you might not get much of an answer for this on the Python mailing
list. I suggest sending your question to the Twisted mailing list instead:
https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python.

On Thu, Sep 1, 2016 at 7:12 AM juraseg  wrote:

> Also, I've tried to find anything in Twisted bug tracker, but I can't find
> my way in there.
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: What should a decorator do if an attribute already exists?

2016-05-16 Thread Kevin Conway
> I have a decorator that adds an attribute to the decorated function

I might try to argue that this is not actually a decorator or, at least,
this is not a great decorator pattern for Python. Adding the attribute to
the function object implies you need to access it at some later point. If
so then your decorator has changed the public interface of the wrapped
item. Downstream code will depend on the new interface which is only
provided by the decorator so it becomes a hard requirement.

IMO, decorators are supposed to be transparent. Removing a decorator should
not invalidate other code.

With your particular example, I believe you are actually implementing a
context manager and the more appropriate code would look like:

with Instrument() as instrument:
#  other code

On Mon, May 16, 2016, 07:23 jmp  wrote:

> On 05/10/2016 05:45 PM, Steven D'Aprano wrote:
> > I have a decorator that adds an attribute to the decorated function:
> [snip]
> > I think 5 is clearly wrong, 4 is too difficult, and 3 seems pointless.
> So I
> > think either 1 or 2 is the right thing to do.
> >
> > Thoughts?
>
> It depends if the attribute "instrument" is part of the public interface.
>
> If not, just find a different name unlikely to clash with an existing
> one *and* raise an exception if it does ever happen anyway.
>
> If the attribute is part of the public interface but you re using the
> code only internally then 1/ raise an exception, otherwise I don't know :o)
>
> It seems to me that over-writing silently (or not) may lead to bugs
> difficult to spot.
>
> jmp
>
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Namespaces are one honking great idea

2016-07-01 Thread Kevin Conway
I believe the namespace object you are referring to is exactly a class.
IIRC, classes came about as a "module in a module".

Regardless, all use cases you've listed are already satisfied by use of the
static and class method decorators. Methods decorated with these do not
require an instance initialization to use.

On Fri, Jul 1, 2016, 20:17 Steven D'Aprano  wrote:

> On Sat, 2 Jul 2016 05:29 am, Ethan Furman wrote:
>
> > On 07/01/2016 10:10 AM, Steven D'Aprano wrote:
> >> On Sat, 2 Jul 2016 02:00 am, Ethan Furman wrote:
> >
> >>> Did you mean for this to go to -Ideas?
> >>
> >> Not yet. I wanted some initial feedback to see if anyone else liked the
> >> idea before taking it to Bikeshedding Central :-)
> >>
> >> Besides, I expect Python-Ideas will say it needs to be a package on PpPI
> >> first. Although I am kinda considering sneaking this into the std lib as
> >> an undocumented internal feature, like simplegeneric in pkgutil. (Don't
> >> tell anyone I said that *wink* )
> >
> > Are there good use-cases for this in the stdlib?
>
> I have at least one.
>
>
>
> --
> Steven
> “Cheer up,” they said, “things could be worse.” So I cheered up, and sure
> enough, things got worse.
>
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Namespaces are one honking great idea

2016-07-02 Thread Kevin Conway
> staticmethod isn't technically required to use a method through the class
(or subclasses), it simply provides the appropriate magic to allow it to be
called through instances.

For example, the following code covers all described use cases of the
proposed namespace. Methods are invoked without creating instances and
state is managed on the class object directly.

class CustomNs:

stateful_data = 1

@staticmethod
def echo(text):
print(text)

@classmethod
def mutate(cls):
cls.stateful_data += 1
print(cls.stateful_data)

CustomNs.echo("test")
print(CustomNs.stateful_data)
CustomNs.mutate()
print(CustomNs.stateful_data)

For the proponents of namespace, what is deficient in the above example
that necessitates a language change?

On Sat, Jul 2, 2016, 00:02 Random832  wrote:

> On Fri, Jul 1, 2016, at 21:50, Kevin Conway wrote:
> > I believe the namespace object you are referring to is exactly a
> > class. IIRC, classes came about as a "module in a module".
>
> No, because classes have instances. And conceptually they seem like they
> *should* have instances. Just using the term "class" carries
> expectations.
>
> More to the point, what modules do that classes do not is provide a
> global namespace for functions defined within them, so that variables
> within them can be used (well, read - writing them requires a
> declaration) by the functions without extra qualification.
>
> > Regardless, all use cases you've listed are already satisfied by use
> > of the static and class method decorators. Methods decorated with
> > these do not require an instance initialization to use.
>
> staticmethod isn't technically required to use a method through the
> class (or subclasses), it simply provides the appropriate magic to allow
> it to be called through instances.
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Namespaces are one honking great idea

2016-07-03 Thread Kevin Conway
>> Regardless, all use cases you've listed are already satisfied by use of
>> the static and class method decorators. Methods decorated with these do
>> not require an instance initialization to use.

> And are significantly less easy to use, as the functions MUST refer to
each
> other by their dotted names.

My response to this may come off as a bit glib, but it isn't intended that
way. If the problem with using classes to satisfy the namespace need is
that it's unwieldy to use dot qualified paths then isn't that quite similar
to saying namespaces are unwieldy? Leveraging classes as a nested module
creates a de-facto internal namespace of "cls" for self reference and I'm
unsure of why that is unwanted but "module.namespace.blah" is wanted.

I suppose my issue is not so much that namespace objects are a bad idea as
that the proposal does little to express why the existing tools are
deficient enough to require a new concept.

> For the proponents of namespace, what is deficient in the above example
> that necessitates a language change?

>> It's not a language change.

Perhaps. My argument is that anything that introduces a new class-like
construct and set of lexical scoping rules is a language change. For
example, if this change went into 2.7.13 would Jython suddenly be broken
because it hasn't implemented the new scoping rules?

>> IIRC, classes came about as a "module in a module".

> I'm pretty sure they did not. Object oriented programming (and hence
> classes) came about from simulating real world objects, hence the
> name:

I realize my statement was ambiguous. I didn't mean to suggest that
classes, as an idea and OOP tool, were derived from the concept of a
namespace. I meant to say that the Python implementation of classes is
quite similar to the implementation of modules in the cPython code. The
commit messages from the earlier days (ref: ab5db02) don't carry much
detail so I'm mostly basing my belief of the implementation similarities
and anecdotes from the community. Right or wrong, I don't believe it has
much weight in the namespace discussion and I shouldn't have brought it up.

On Sun, Jul 3, 2016, 00:17 Ethan Furman  wrote:

> On 07/02/2016 08:44 PM, Steven D'Aprano wrote:
>
> > Try getting this behaviour from within a class:
> >
> >
> > class Food(metaclass=Namespace):
> >
> >  # (1) no special decorators required
> >  def spam(n):
> >  return ' '.join(['spam']*n)
> >
> >  # (2) can call functions from inside the namespace
> >  breakfast = spam(5)
> >
> >  # (3) no "cls" or "self" argument
> >  def lunch():
> >  # (4) can access variables using their undotted name
> >  return breakfast + ' and eggs'
> >
> >  def supper():
> >  # (5) likewise functions (a special case of #4)
> >  return lunch() + ' and a fried slice of spam'
> >
> >  def mutate(n):
> >  # global inside the namespace refers to the namespace,
> >  # not the surrounding module
> >  global breakfast
> >  breakfast = spam(5)
>
> > Can you do all of that with an ordinary class?
>
> You can get #2 already, but not the rest (without your spiffy code ;) :
>
> Python 3.5.1+ (3.5:f840608f79da, Apr 14 2016, 12:29:06)
> [GCC 4.8.2] on linux
> Type "help", "copyright", "credits" or "license" for more information.
>  >>> class Huh:
> ...   def blah(text):
> ... print('blah blah %s blah blah blah' % text)
> ...   blah('whatever')
> ...
> blah blah whatever blah blah blah
>
> --
> ~Ethan~
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Cannot step through asynchronous iterator manually

2016-01-30 Thread Kevin Conway
To address the original question, I don't believe a next() equivalent for
async iterables has been added to the standard library yet. Here's an
implementation from one of my projects that I use to manually get the next
value: https://bpaste.net/show/e4bd209fc067. It exposes the same interface
as the synchronous next(). Usage:

await anext(some_async_iterator)

Ultimately, it's a fancy wrapper around the original snippet of 'await
iterator.__anext__()'.


On Sat, Jan 30, 2016 at 6:07 AM Maxime S  wrote:

> 2016-01-30 11:51 GMT+01:00 Frank Millman :
>
> > "Chris Angelico"  wrote in message
> > news:CAPTjJmoAmVNTCKq7QYaDRNQ67Gcg9TxSXYXCrY==s9djjna...@mail.gmail.com.
> ..
> >
> >
> >> On Sat, Jan 30, 2016 at 7:22 PM, Frank Millman 
> >> wrote:
> >> > We had a recent discussion about the best way to do this, and ChrisA
> >> > suggested the following, which I liked -
> >> >
> >> >cur.execute('SELECT ...)
> >> >try:
> >> >row = next(cur)
> >> >except StopIteration:
> >> ># row does not exist
> >> >else:
> >> >try:
> >> >next_row = next(cur)
> >> >except StopIteration:
> >> ># row does exist
> >> >else:
> >> ># raise exception
> >> >
> >> > Now that I have gone async, I want to do the same with an asynchronous
> >> > iterator.
> >>
> >
> >
> I might be a bit off-topic, but why don't you simply use cursor.rowcount?
>
> For a pure iterator-based solution, I would do something like this (admitly
> a bit cryptic, but iterator-based solutions often are :-) :
>
> async def get_uniqu(ait):
> async for row in ait:
> break
> else:
> raise NotEnoughtRows()
> async for _ in ait:
> raise TooManyRows()
> return row
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Cannot step through asynchronous iterator manually

2016-01-30 Thread Kevin Conway
> Any particular reason not to use the classic sentinel object model?

None that I can remember. I would use the sentinel pattern if I were
writing it again today.

> Also curious is that you raise a new StopAsyncIteration from the original
one, rather than just reraising the original. I assume there's a reason for
that, but it doesn't have a comment.

I think I was just playing around with the new syntax.

I also just noticed that there is an inconsistent use of the terms iterator
and iterable in the docstring and variable names. The function looks much
improved after updates: https://bpaste.net/show/14292d2b4070. Thanks for
calling that out.

Note to self: Review old code before copy/pasta into the mail list.

On Sat, Jan 30, 2016 at 6:57 AM Chris Angelico  wrote:

> On Sat, Jan 30, 2016 at 11:35 PM, Kevin Conway
>  wrote:
> > To address the original question, I don't believe a next() equivalent for
> > async iterables has been added to the standard library yet. Here's an
> > implementation from one of my projects that I use to manually get the
> next
> > value: https://bpaste.net/show/e4bd209fc067. It exposes the same
> interface
> > as the synchronous next(). Usage:
> >
> > await anext(some_async_iterator)
> >
> > Ultimately, it's a fancy wrapper around the original snippet of 'await
> > iterator.__anext__()'.
>
> Curious idiom for the one-or-two-arg situation. Any particular reason
> not to use the classic sentinel object model?
>
> _SENTINEL = object()
> async def anext(iterable, default=_SENTINEL):
> ...
> if default is not _SENTINEL:
> return default
>
> Or if you want to avoid that, at least take iterable as a fixed arg:
>
> async def anext(iterable, *default):
> if len(default) > 1: TypeError
> ...
> if default: return default[0]
>
> Also curious is that you raise a new StopAsyncIteration from the
> original one, rather than just reraising the original. I assume
> there's a reason for that, but it doesn't have a comment.
>
> ChrisA
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: How a module is being marked as imported?

2016-02-04 Thread Kevin Conway
As an attempt to answer your original question, Python doesn't explicitly
mark a module as done. It does keep imports cached in sys.modules, though.
The behaviour you describe where later imports get the same module object
is driven by that cache.

There are cases, such as cyclical imports, where the object in sys.modules
is empty for a period of time and acts as a placeholder until the code from
that module is loaded. During that time, any usage of the module would
result in a similar failure to what you have described.

Additionally, if you are writing multithreaded code then acquiring the GIL
may not be enough. There is another lock used for imports.

On Thu, Feb 4, 2016, 09:43 Jean-Charles Lefebvre 
wrote:

> So far, I've been advised to:
>
> 1/ Double-check that the GIL was correctly acquired
> 2/ Ensure there's no 'string' module in my project
> 3/ Manually pre-import commonly used standard modules at interpreter's
> init-time to avoid race conditions due to the multi-threaded nature of the
> running environment
>
> No problem found for 1/ & 2/ (double-checked). I tried 3/ before posting
> and could not reproduce the problem at all which is probably the patch I
> will apply due to the lack of a better solution. I guess I'll have to dig
> into __import__'s code and related.
>
>
> On Thursday, February 4, 2016 at 11:20:05 AM UTC+1, Jean-Charles Lefebvre
> wrote:
> > Hi all,
> >
> > The short version: How CPython marks a module as being fully imported,
> if it does, so that the same import statement ran from another C thread at
> the same time does not collide? Or, reversely, does not think the module is
> not already fully imported?
> >
> > The full version: I'm running CPython 3.5.1, embedded into a C++
> application on Windows. The application is heavily multi-threaded so
> several C threads call some Python code at the same time (different Python
> modules), sharing interpreter's resources by acquiring/releasing the GIL
> frequently DURING the calls, at language boundaries.
> >
> > Sometimes (but always only once per application instance), a call to
> os.path.expandvars raises the AttributeError exception with message: module
> 'string' has no attribute 'ascii_letters'. It is raised by the
> ntpath.expandvars function (line 372). When I noticed the late import
> statement of the 'string' module at the line above, I thought that MAYBE,
> it could be because the interpreter is ran in an heavily multi-threaded
> environment and that the GIL acquiring/releasing occurred at a bad timing?
> Making me wonder how the import mechanism interacts with the GIL, if it
> does?
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Python's import situation has driven me to the brink of imsanity

2016-02-06 Thread Kevin Conway
> My question is: is this crazy? Please tell me there's a better way and I
just wasted my time creating this package.

There is a better way and you have wasted your time creating this package.

I hear your problem statement as asking two questions. The first is: What
is the right way to include executable content in my Python project? The
second is: How do I expose executable content from a Python project?

As to the first question, from your project README:
> Say you have a python project (not a package), with the following
structure:

All Python code that you want to install and make available in any form,
import or executable, _must_ be contained within a Python package.
Organizing Python code in any way other than Python packages will result in
the challenges you have described. The correct way to include executable
content is to place the Python code within the package structure. It should
not be put in other directories within the repository root.

As to the second question, once all Python code is contained within a
package that can be installed you can use setuptools entry points to expose
the executable code. The setup() function from setuptools that is used to
create setup.py files has an argument called 'entry_points' that allows you
to expose executable content over the command line. See [1] and [2] for
more details.

Feel free to reach out to me off-list if you have a specific project you
need advice on. The rules for organizing and packaging Python code aren't
complex but they tend to cause new Python developers to stumble at first. A
general rule I give everyone when talking about packaging or importing
code: If you have to modify sys.path to makes something work then you have
most certainly made a mistake.

[1]
https://pythonhosted.org/setuptools/setuptools.html#automatic-script-creation
[2]
http://python-packaging.readthedocs.org/en/latest/command-line-scripts.html#the-console-scripts-entry-point


On Sat, Feb 6, 2016 at 8:54 PM Chris Angelico  wrote:

> On Sun, Feb 7, 2016 at 1:47 PM,   wrote:
> > Imsanity allows you to make imports usable (not ideal, but at least
> usable) for python projects without having to manage PYTHONPATHs or do
> whacky stuff like running files with python -m or put even whackier
> boilerplate at the top of every file. And all it requires is 'import
> imsanity' at the top of every file. You can put it in a macro or even just
> type it because it's short and easy to remember.
> >
> > My question is: is this crazy? Please tell me there's a better way and I
> just wasted my time creating this package. There's nothing I'd like to hear
> more.
>
> Well, anything that makes you type "import imsanity" at the top of
> every script MUST be crazy. :) I don't know about the actual
> content/purpose though. Good luck with it!
>
> ChrisA
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Python's import situation has driven me to the brink of imsanity

2016-02-07 Thread Kevin Conway
You can use 'setup.py develop' or 'pip install -e' to install your package
in editable mode. It makes it so your local code is used. Modifications are
seen immediately.

On Sun, Feb 7, 2016, 08:16   wrote:

> I see that this would work once you've installed the package, but how do
> you develop it? Say you are working on a change that modifies both email.py
> and reports.py. Do you run setup.py every time you make a change in
> email.py?
>
> On Sunday, February 7, 2016 at 1:35:15 AM UTC-5, Kevin Conway wrote:
> > > My question is: is this crazy? Please tell me there's a better way and
> I
> > just wasted my time creating this package.
> >
> > There is a better way and you have wasted your time creating this
> package.
> >
> > I hear your problem statement as asking two questions. The first is: What
> > is the right way to include executable content in my Python project? The
> > second is: How do I expose executable content from a Python project?
> >
> > As to the first question, from your project README:
> > > Say you have a python project (not a package), with the following
> > structure:
> >
> > All Python code that you want to install and make available in any form,
> > import or executable, _must_ be contained within a Python package.
> > Organizing Python code in any way other than Python packages will result
> in
> > the challenges you have described. The correct way to include executable
> > content is to place the Python code within the package structure. It
> should
> > not be put in other directories within the repository root.
> >
> > As to the second question, once all Python code is contained within a
> > package that can be installed you can use setuptools entry points to
> expose
> > the executable code. The setup() function from setuptools that is used to
> > create setup.py files has an argument called 'entry_points' that allows
> you
> > to expose executable content over the command line. See [1] and [2] for
> > more details.
> >
> > Feel free to reach out to me off-list if you have a specific project you
> > need advice on. The rules for organizing and packaging Python code aren't
> > complex but they tend to cause new Python developers to stumble at
> first. A
> > general rule I give everyone when talking about packaging or importing
> > code: If you have to modify sys.path to makes something work then you
> have
> > most certainly made a mistake.
> >
> > [1]
> >
> https://pythonhosted.org/setuptools/setuptools.html#automatic-script-creation
> > [2]
> >
> http://python-packaging.readthedocs.org/en/latest/command-line-scripts.html#the-console-scripts-entry-point
> >
> >
> > On Sat, Feb 6, 2016 at 8:54 PM Chris Angelico  wrote:
> >
> > > On Sun, Feb 7, 2016 at 1:47 PM,   wrote:
> > > > Imsanity allows you to make imports usable (not ideal, but at least
> > > usable) for python projects without having to manage PYTHONPATHs or do
> > > whacky stuff like running files with python -m or put even whackier
> > > boilerplate at the top of every file. And all it requires is 'import
> > > imsanity' at the top of every file. You can put it in a macro or even
> just
> > > type it because it's short and easy to remember.
> > > >
> > > > My question is: is this crazy? Please tell me there's a better way
> and I
> > > just wasted my time creating this package. There's nothing I'd like to
> hear
> > > more.
> > >
> > > Well, anything that makes you type "import imsanity" at the top of
> > > every script MUST be crazy. :) I don't know about the actual
> > > content/purpose though. Good luck with it!
> > >
> > > ChrisA
> > > --
> > > https://mail.python.org/mailman/listinfo/python-list
> > >
>
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: asyncio - run coroutine in the background

2016-02-16 Thread Kevin Conway
If you're handling coroutines there is an asyncio facility for "background
tasks". The ensure_future [1] will take a coroutine, attach it to a Task,
and return a future to you that resolves when the coroutine is complete.
The coroutine you schedule with that function will not cause your current
coroutine to wait unless you await the future it returns.

[1]
https://docs.python.org/3/library/asyncio-task.html#asyncio.ensure_future

On Mon, Feb 15, 2016, 23:53 Chris Angelico  wrote:

> On Mon, Feb 15, 2016 at 6:39 PM, Paul Rubin 
> wrote:
> > "Frank Millman"  writes:
> >> The benefit of my class is that it enables me to take the coroutine
> >> and run it in another thread, without having to re-engineer the whole
> >> thing.
> >
> > Threads in Python don't get you parallelism either, of course.
> >
>
> They can. The only limitation is that, in CPython (and some others),
> no two threads can concurrently be executing Python byte-code. The
> instant you drop into a C-implemented function, it can release the GIL
> and let another thread start running. Obviously this happens any time
> there's going to be a blocking API call (eg if one thread waits on a
> socket read, others can run), but it can also happen with
> computational work:
>
> import numpy
> import threading
>
> def thread1():
> arr = numpy.zeros(1, dtype=numpy.int64)
> while True:
> print("1: %d" % arr[0])
> arr += 1
> arr = (arr * arr) % 142957
>
> def thread2():
> arr = numpy.zeros(1, dtype=numpy.int64)
> while True:
> print("2: %d" % arr[0])
> arr += 2
> arr = (arr * arr) % 142957
>
> threading.Thread(target=thread1).start()
> thread2()
>
> This will happily keep two CPU cores occupied. Most of the work is
> being done inside Numpy, which releases the GIL before doing any work.
> So it's not strictly true that threading can't parallelise Python code
> (and as mentioned, it depends on your interpreter - Jython can, I
> believe, do true multithreading), but just that there are limitations
> on what can execute concurrently.
>
> ChrisA
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: asyncio - run coroutine in the background

2016-02-16 Thread Kevin Conway
> Ok, yes, but those "background tasks" monopolize the CPU once they are
scheduled to run.

This is true if the coroutines are cpu bound. If that is the case then a
coroutine is likely the wrong choice for that code to begin with.
Coroutines, in asyncio land, are primarily designed for io bound work.

> My background task does take a long time to run - about 10 seconds - but
most of that time is spent waiting for database responses, which is handled
in another thread.

Something else to look into is an asyncio driver for your database
connections. Threads aren't inherently harmful, but using them to achieve
async networking when running asyncio is a definite code smell since that
is precisely the problem asyncio is supposed to solve for.

On Tue, Feb 16, 2016, 08:37 Frank Millman  wrote:

> "Marko Rauhamaa"  wrote in message news:[email protected].
> ..
> >
> > Kevin Conway :
> >
> > > If you're handling coroutines there is an asyncio facility for
> > > "background tasks". The ensure_future [1] will take a coroutine,
> > > attach it to a Task, and return a future to you that resolves when the
> > > coroutine is complete.
> >
> > Ok, yes, but those "background tasks" monopolize the CPU once they are
> > scheduled to run.
> >
> > If your "background task" doesn't need a long time to run, just call the
> > function in the foreground and be done with it. If it does consume time,
> > you need to delegate it to a separate process so the other tasks remain
> > responsive.
> >
>
> I will explain my situation - perhaps you can tell me if it makes sense.
>
> My background task does take a long time to run - about 10 seconds - but
> most of that time is spent waiting for database responses, which is handled
> in another thread.
>
> You could argue that the database thread should rather be handled by
> another
> process, and that is definitely an option if I find that response times are
> affected.
>
> So far my response times have been very good, even with database activity
> in
> the background. However, I have not simulated a large number of concurrent
> users. That could throw up the kinds of problem that you are concerned
> about.
>
> Frank
>
>
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: asyncio - run coroutine in the background

2016-02-20 Thread Kevin Conway
> getaddrinfo is a notorious pain but I think it's just a library issue; an
async version should be possible in principle.  How does Twisted handle
it?  Does it have a version?

I think we're a little outside the scope of OP's question at this point,
but for the sake of answering this:

There are a few cases that I know of where Twisted uses the standard lib
socket DNS methods. One is when resolving names to IPv6 addresses [1] when
creating a client connection to a remote source. The other is in the
default DNS resolver that is installed in the reactor [2]. Creating client
connections allows the call to 'getaddrinfo' to block without mitigation.
The default DNS resolver, unfortunately, dispatches calls of
'gethostbyname' to a thread pool.

Without seeing the commit history, I'd assume the use of 'socket' and
threads by default is an artifact that predates the implementation of the
DNS protocol in Twisted. Twisted has, in 'twisted.names' [3], a DNS
protocol that uses UDP and leverages the reactor appropriately. Thankfully,
Twisted has a reactor method called 'installResolver' [4] that allows you
to hook in any DNS resolver implementation you want so you aren't stuck
using the default, threaded implementation.

As far as asyncio, it also defaults to an implementation that delegates to
an executor (default: threadpool). Unlike Twisted, though, it appears to
require a subclass of the event loop to override the 'getaddrinfo' method
[5].

[1]
https://github.com/twisted/twisted/blob/trunk/twisted/internet/tcp.py#L622
[2]
https://github.com/twisted/twisted/blob/trunk/twisted/internet/base.py#L257
[3] https://github.com/twisted/twisted/tree/trunk/twisted/names
[4]
https://github.com/twisted/twisted/blob/trunk/twisted/internet/base.py#L509
[5]
https://github.com/python/cpython/blob/master/Lib/asyncio/base_events.py#L572

On Sat, Feb 20, 2016, 03:31 Marko Rauhamaa  wrote:

> Paul Rubin :
>
> > I've just felt depressed whenever I've looked at any Python async
> > stuff. I've written many Python programs with threads and not gotten
> > into the trouble that people keep warning about.
>
> Programming-model-wise, asyncio is virtually identical with threads. In
> each, I dislike the implicit state concept. I want the state to stand
> out with big block letters.
>
> > I've just felt depressed whenever I've looked at any Python async
> > stuff. I've written many Python programs with threads and not gotten
> > into the trouble that people keep warning about. But I haven't really
> > understood the warnings, so maybe they know something I don't. I just
> > write in a multiprocessing style, with every mutable object owned by
> > exactly one thread and accessed only by RPC through queues, sort of a
> > poor man's Erlang. There's a performance hit but there's a much bigger
> > one from using Python in the first place, so I just live with it.
>
> Good for you if you have been able to choose your own programming model.
> Most people have to deal with a legacy mess. Also, maintainers who
> inherit your tidy code might not be careful to ship only nonmutable
> objects in the queues.
>
> Your way of using threads works, of course, with the caveat that it is
> not possible to get rid of a blocking thread from the outside. With
> asyncio, you can at least cancel tasks.
>
>
> Marko
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list