Commit 78d85cdc authored by Kirill Smelkov's avatar Kirill Smelkov

sync: threading.Event -> chan

Starting from e6bea2cf (sync: New package that mirrors Go's sync) there
is sync.WaitGroup and it was using threading.Event to signal that
waitgroup's counter dropped to zero. threading.Event is implemented in
Python's stdlib via threading.Condition, which in turn uses
threading.Lock and list of waiters to implement its functionality.
Which in turn is very similar to what golang.chan does internally with
semaphore and e.g. recv queue.

I noticed this while debugging sync test deadlock (see previous patch)
and suspecting bug in threading.Event for a moment. While it turned
there is no bug in threading.Event, it is better to rely on the common
functionality for similar tasks, and pygolang's channel perfectly
matches here the need to signal an event. By using our own code instead
of stdlib's threading we are likely becoming less bug-prone.

This also brings a small speedup:

    (on i5@1.80GHz)
    name             old time/op  new time/op  delta
    workgroup_empty   239µs ± 1%   220µs ± 1%  -7.62%  (p=0.000 n=10+9)
    workgroup_raise   275µs ± 2%   264µs ± 2%  -3.85%  (p=0.000 n=10+10)
parent b8b042c5
...@@ -27,7 +27,7 @@ See the following link about Go sync package: ...@@ -27,7 +27,7 @@ See the following link about Go sync package:
from __future__ import print_function, absolute_import from __future__ import print_function, absolute_import
import threading, sys import threading, sys
from golang import go, defer, func, panic from golang import go, chan, defer, func, panic
from golang import context from golang import context
import six import six
...@@ -56,7 +56,7 @@ class WaitGroup(object): ...@@ -56,7 +56,7 @@ class WaitGroup(object):
def __init__(wg): def __init__(wg):
wg._mu = threading.Lock() wg._mu = threading.Lock()
wg._count = 0 wg._count = 0
wg._event = threading.Event() wg._done = chan() # closed & recreated every time ._count drops to 0
def done(wg): def done(wg):
wg.add(-1) wg.add(-1)
...@@ -69,15 +69,15 @@ class WaitGroup(object): ...@@ -69,15 +69,15 @@ class WaitGroup(object):
if wg._count < 0: if wg._count < 0:
panic("sync: negative WaitGroup counter") panic("sync: negative WaitGroup counter")
if wg._count == 0: if wg._count == 0:
wg._event.set() wg._done.close()
wg._event = threading.Event() wg._done = chan()
def wait(wg): def wait(wg):
with wg._mu: with wg._mu:
if wg._count == 0: if wg._count == 0:
return return
event = wg._event done = wg._done
event.wait() done.recv()
# WorkGroup is a group of goroutines working on a common task. # WorkGroup is a group of goroutines working on a common task.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment