[Python-ideas] Atomic counter / atomic increment

2016-08-25 Thread Ben Hoyt
I had to implement a simple atomic counter the other day to count the total
number of requests processed in a multi-threaded Python web server.

I was doing a demo of "how cool Python is" to my colleagues, and they were
generally wowed, but one of the things that made them do a double-take
(coming mostly from Scala/Java) was that there was no atomic counter in the
standard library.

The fact that I and many other folks have implemented such things makes me
wonder if it should be in the standard library.

It's pretty simple to implement, basically the handful of lines of code
below (full version on GitHub Gist at
https://gist.github.com/benhoyt/8c8a8d62debe8e5aa5340373f9c509c7):

import threading

class AtomicCounter:
def __init__(self, initial=0):
self.value = initial
self._lock = threading.Lock()

def increment(self, num=1):
with self._lock:
self.value += num
return self.value

And if you just want a one-off and don't want to write a class, it's like
so:

import threading

counter_lock = threading.Lock()
counter = 0

with counter_lock:
counter += 1
value = counter
print(value)

But it could be this much more obvious code:

import threading
counter = threading.AtomicCounter()
value = counter.increment()
print(value)

Thoughts? Would such a class make a good candidate for the standard
library? (API could probably be improved.)

-Ben
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] Atomic counter / atomic increment

2016-08-25 Thread M.-A. Lemburg
On 25.08.2016 19:31, Ben Hoyt wrote:
> I had to implement a simple atomic counter the other day to count the total
> number of requests processed in a multi-threaded Python web server.
> 
> I was doing a demo of "how cool Python is" to my colleagues, and they were
> generally wowed, but one of the things that made them do a double-take
> (coming mostly from Scala/Java) was that there was no atomic counter in the
> standard library.
> 
> The fact that I and many other folks have implemented such things makes me
> wonder if it should be in the standard library.

As long as Python uses a GIL to protect C level function
calls, you can use an iterator for this:

import itertools
x = itertools.count()
...
mycount = next(x)
...

The trick here is that the CALL_FUNCTION byte code will trigger
the increment of the iterator. Since this is implemented in C,
the GIL will serve as lock on the iterator while it is
being incremented.

With Python 4.0, this will all be different, though :-)

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Experts (#1, Aug 25 2016)
>>> Python Projects, Coaching and Consulting ...  http://www.egenix.com/
>>> Python Database Interfaces ...   http://products.egenix.com/
>>> Plone/Zope Database Interfaces ...   http://zope.egenix.com/


::: We implement business ideas - efficiently in both time and costs :::

   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
   Registered at Amtsgericht Duesseldorf: HRB 46611
   http://www.egenix.com/company/contact/
  http://www.malemburg.com/

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Atomic counter / atomic increment

2016-08-25 Thread Ben Hoyt
> As long as Python uses a GIL to protect C level function
> calls, you can use an iterator for this:
>
> import itertools
> x = itertools.count()
> ...
> mycount = next(x)
>

Yeah, that's a neat hack -- I saw it recommended on StackOverflow, and saw
it used in the standard library somewhere. I think that's probably okay in
the *CPython* stdlib, because it's CPython so you know it has the GIL. But
this wouldn't work in other Python implementations, would it (IronPython
and Jython don't have a GIL). Or when itertools.count() is implemented in
pure Python on some system? Seems like it could blow up in someone's face
when they're least expecting it. I also think using *iter*tools is a pretty
non-obvious way to get a thread-safe counter.

-Ben
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] Atomic counter / atomic increment

2016-08-25 Thread M.-A. Lemburg
On 25.08.2016 20:10, Ben Hoyt wrote:
>> As long as Python uses a GIL to protect C level function
>> calls, you can use an iterator for this:
>>
>> import itertools
>> x = itertools.count()
>> ...
>> mycount = next(x)
>>
> 
> Yeah, that's a neat hack -- I saw it recommended on StackOverflow, and saw
> it used in the standard library somewhere. I think that's probably okay in
> the *CPython* stdlib, because it's CPython so you know it has the GIL. But
> this wouldn't work in other Python implementations, would it (IronPython
> and Jython don't have a GIL). Or when itertools.count() is implemented in
> pure Python on some system? Seems like it could blow up in someone's face
> when they're least expecting it. I also think using *iter*tools is a pretty
> non-obvious way to get a thread-safe counter.

All true.

Having an implementation in threading which hides away the
details would be nice. On CPython using iterators would
certainly be one of the most efficient ways of doing this.

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Experts (#1, Aug 25 2016)
>>> Python Projects, Coaching and Consulting ...  http://www.egenix.com/
>>> Python Database Interfaces ...   http://products.egenix.com/
>>> Plone/Zope Database Interfaces ...   http://zope.egenix.com/


::: We implement business ideas - efficiently in both time and costs :::

   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
   Registered at Amtsgericht Duesseldorf: HRB 46611
   http://www.egenix.com/company/contact/
  http://www.malemburg.com/

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Atomic counter / atomic increment

2016-08-25 Thread Guido van Rossum
The only reason I can think of for wanting this simple class in the stdlib
would be that on GIL-free Python implementations you could replace it with
a lock-free version. But I think we'd probably want to rethink a bunch of
other datastructures to be lock-free, and a 3rd party package on PyPI makes
more sense to me than jumping right into the stdlib.

On Thu, Aug 25, 2016 at 11:10 AM, Ben Hoyt  wrote:

>
> As long as Python uses a GIL to protect C level function
>> calls, you can use an iterator for this:
>>
>> import itertools
>> x = itertools.count()
>> ...
>> mycount = next(x)
>>
>
> Yeah, that's a neat hack -- I saw it recommended on StackOverflow, and saw
> it used in the standard library somewhere. I think that's probably okay in
> the *CPython* stdlib, because it's CPython so you know it has the GIL. But
> this wouldn't work in other Python implementations, would it (IronPython
> and Jython don't have a GIL). Or when itertools.count() is implemented in
> pure Python on some system? Seems like it could blow up in someone's face
> when they're least expecting it. I also think using *iter*tools is a pretty
> non-obvious way to get a thread-safe counter.
>
> -Ben
>
>
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>



-- 
--Guido van Rossum (python.org/~guido)
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] Atomic counter / atomic increment

2016-09-07 Thread Koos Zevenhoven
> import threading
>
> class AtomicCounter:
> def __init__(self, initial=0):
> self.value = initial
> self._lock = threading.Lock()
>
> def increment(self, num=1):
> with self._lock:
> self.value += num
> return self.value

Some late nitpicking, sorry:

This is not an atomic counter, it's a thread-safe counter. And since
being thread-safe is rarely a bad idea, especially assuming someone
will manage to Kill GIL, I would just call it a "counter" or Counter.

(Of course, atomic/lock-free implementations are nice when possible.)

-- Koos
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/