Thursday, October 30, 2014

thread safe generator.

Generators are not thread safe, this example triggers the error:

"""
generator are not thread safe, two or more thread accessing the same generator
causes an error:
ValueError: generator already executing
example comes from:
http://stackoverflow.com/questions/20043472/python-multithreading-why-generators-are-not-thread-safe-what-happens-when-it
"""
import threading
class CountThread(threading.Thread):
def __init__(self, gen):
super(CountThread, self).__init__()
self.gen = gen
self.number_seen = 0
def run(self):
# does nothing but counting
for i in self.gen:
self.number_seen += 1
# shortcut generator expression, or you can write with yeild
igen = (i for i in xrange(10000))
t = [CountThread(igen), CountThread(igen)]
[tt.start() for tt in t]
[tt.join() for tt in t]

You can fix it with a lock, which is considered cheaper than using a queue.

"""
generator are not thread safe, two or more thread accessing the same generator
causes an error:
ValueError: generator already executing
example comes from:
http://stackoverflow.com/questions/20043472/python-multithreading-why-generators-are-not-thread-safe-what-happens-when-it
but you can make it safe with a lock
the idea comes while reading joblib source code
"""
import threading
class LockedIterator(object):
def __init__(self, it):
self._lock = threading.Lock()
self._it = it
def __iter__(self):
return self
def next(self):
with self._lock:
return next(self._it)
# python 3 compat
__next__ = next
class CountThread(threading.Thread):
def __init__(self, gen):
super(CountThread, self).__init__()
self.gen = gen
self.number_seen = 0
def run(self):
# does nothing but counting
for i in self.gen:
self.number_seen += 1
def __repr__(self):
return "(seen: {})".format(self.number_seen)
# shortcut generator expression, or you can write with yeild
igen = (i for i in xrange(10000))
igen_safe = LockedIterator(igen)
t = [CountThread(igen_safe), CountThread(igen_safe)]
[tt.start() for tt in t]
[tt.join() for tt in t]
print 'sum should be 10000'
print t

Wednesday, October 29, 2014

Decoration, Pickle, Closure.

What is closure? What it has to do with pickle-able ? 

A closure occurs when a function has access to a local variable from an enclosing scope that has finished its execution.
Here is an example, test2 doesn't work because pickle works with name. test3 doesn't work because it conflicts with top-level function 'foo'

from functools import wraps
import pickle
import sys
def foo(x):
def bar():
return x**2
return bar
if __name__ == '__main__':
try:
c = int(raw_input('input 1,2,3 to choose which test to run: '))
except ValueError:
print 'not a number'
# this will work, because pickle needs a name
if c == 1:
print 'test1'
bar = foo(2)
with open('./delme', 'w') as ff:
pickle.dump(bar, ff)
elif c == 2:
print 'test2'
# this will not work, because pickle needs a name
with open('./delme', 'w') as ff:
pickle.dump(foo(2), ff)
elif c == 3:
print 'test3'
# this will not work, because of the name conflict
foo = foo(2)
with open('./delme', 'w') as ff:
pickle.dump(foo, ff)
else:
print 'input out of range'
view raw closure_2.py hosted with ❤ by GitHub


Pickle, Decorator. 

The decorated function has the same name as the original function, makes it un-pickle-able.

from functools import wraps
import pickle
import sys
def logged(func):
"""
if not wrapped, the decoreated function has the same name as the original
cannot pickle
"""
# @wraps(func)
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging
def f(x):
"""does some math
"""
return x**2
if __name__ == '__main__':
try:
c = int(raw_input("input 1,2,3: "))
except ValueError:
print 'not an int'
if c == 1:
"""
this doesn't work because the name conflict
"""
print 'test1'
"""
note this is equivalent to decoration syntax:
@logged
def f(x) ....
"""
f = logged(f)
print f(2)
# name is with_logging, lose of function information
print f.__name__
with open('./delme', 'w') as ff:
pickle.dump(f, ff)
elif c == 2:
"""
this works, the returned fucntion name has to match __name__
which is 'with_logging' in our case, this is a huge limitation.
for example, in debugging
"""
print 'test2'
with_logging = logged(f)
print with_logging(2)
# name is with_logging, lose of function information
print with_logging.__name__
with open('./delme', 'w') as ff:
pickle.dump(with_logging, ff)
elif c == 3:
"""
wraps() is also a decorator that updates the function information
such as names ....
it takes a function as a parameter
using wraps() is equivalent to
@wraps(func)
def with_logging( ...
"""
# this works
print 'test3'
f = wraps(f)(logged(f))
print f(2)
# no lose of function information
print f.__name__
with open('./delme', 'w') as ff:
pickle.dump(f, ff)
view raw wraps.py hosted with ❤ by GitHub
the right way to write a decorator function is to always use 'wraps'. Be able to pickled is crucial when you programming multiprocess.


Sunday, October 26, 2014

Solution of over sensitive touch pad, Linux

Install ubuntu on VAIO ultrabook. The large touchpad is too sensitive that it often register my palm.

The palm detection can be fine-tuned, but here is a solution if you don't need that large a touchpad, and you want to 'tap-to-click'

open a terminal, use the 'synclient' command to find the current setting of your touchpad. The LeftEdge, RightEdge, TopEdge, and BottomEdge tells you roughly the dimension of your touchpad.

then you can use 'synclient AreaRightEdge=5000' to reduce the dimension of your touch pad. You may want to finetune it yourself. If the number is too small, that might deactivate your touchpad, don't worry, just set it to a larger number.