Executing previous stack frame

sturlamolden sturlamolden at yahoo.no
Thu Jan 22 16:16:29 EST 2009


On Jan 22, 8:47 pm, Jeff McNeil <j... at jmcneil.net> wrote:

> What are you trying to accomplish?


On Jan 22, 8:47 pm, Jeff McNeil <j... at jmcneil.net> wrote:

> What are you trying to accomplish?  While it's possible to do, I can't
> believe it's going to be very safe.

I am trying to implement a completely new concurrency abstraction for
Python. It is modeled on OpenMP instead of Java threads (cf. threading
and multiprocessing). I am planning to use thread and multiprocessing
(or os.fork) as backends. Doing this with os.fork is child's play, but
it would not work on Windows.

I believe Python context managers are excellent for this purpose. I
believe the OpenMP way of doing concurrency fits better with the mind
than Java threading, and thus are more pythonic. Algorithms can be
written as sequential, and transformed to parallel code with the
simple insertion of a few directives. It makes debugging easier,
because one can debug the sequential code, and it makes it easier to
avoid the problems with deadlocks, race conditions, livelocks, etc.
Just ask any C or Fortran programmer how much easier it is to use
OpenMP instead of Win32 or Posix threads.

What I have in mind is an API that would look approximately like this
(OpenMP pragmas for C on top, proposed Python equivalent below):


#pragma omp parallel
with Pool() as pool:

#pragma omp for
for item in pool.parallel(<iterable>):

#pragma omp for shedule(guided)
for item in pool.parallel(<iterable>, shed='guided'):

#pragma omp parallel for
with Pool() as pool:
    for item in pool.parallel(<iterable>):

#pragma omp barrier
pool.barrier()

#pragma omp section
with pool.section():

#pragma omp parallel sections
with Pool() as pool:
    with pool.section():
       fun1(*args, **kwargs)
    with pool.section():
       fun2(*args, **kwargs)

#pragma omp master
if pool.master:

#pragma omp critical
#pragma omp atomic
with pool.lock:

#pragma omp single
with pool.single():

#pragma omp ordered
with ordered(k):


Here is a toy example of what I have in mind. Say you would want to
compute the DFT of some signal (real apps would use an FFT in C for
this, but never mind that). In Python using an O(n**2) algorithm, this
would look like something like this:


def real_dft(x):
    ''' DFT for a real valued sequence x '''
    r = []
    N = len(x)
    M = N//2 + 1 if N%2 else N//2
    for n in range(M):
       s = 0j
       for k in range(N):
          tmp = 2*pi*k*n/N
          s += x[k] * (cos(tmp) - 1j*sin(tmp))
       r.append(s)
    return r


Then, one could 'magically' transform this algorithm into to a
parallel one simply by inserting directives from the 'OpenMP' module:


def real_dft(x):
    ''' DFT for a real valued sequence x '''
    ''' parallelized '''
    r = []
    N = len(x)
    M = N//2 + 1 if N%2 else N//2
    with Pool() as pool:
       parallel_iter = pool.parallel(range(M)):
       for n in parallel_iter:
          s = 0j
          for k in range(N):
             tmp = 2*pi*k*n/N
             s += x[k] * (cos(tmp) - 1j*sin(tmp))
          with parallel_iter.ordered(n):
             r.append(s)
    return r


The idea is that 'parallelizing' a sequential algorithm like this is
much easier than writing a parallel one from scratch using the
abstractions in threading or multiprocessing.

The problem is that the __enter__ method of the Pool object (the
context manager) must spawn multiple threads, each executing
sys._getframe().f_back, because the 'with Pool() as pool:' should be
executed by multiple threads in parallel. These slave threads will be
killed when they enter the __exit__ method of its context manager.

Most of this OpenMP API has already been implemented. I just need the
machinery to make the slave threads come alive :)

I'll take a look at your code now :)



Regards,
Sturla Molden



More information about the Python-list mailing list