ciptamf / pypar

Automatically exported from code.google.com/p/pypar
0 stars 0 forks source link

Pypar does not release GIL when calling blocking routines #4

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
It is desirable for pypar to release the GIL when calling blocking routines 
such as MPI_recv. This way communication can be made threaded within each MPI 
program instance.  This is especially problematic for my use case because pypar 
has no non-blocking alternative calls. 

The following python snippet, though of no practical use, illustrates the issue 
when run on two processors.

import time, threading, pypar, random

message = None

def communicator_thread() :
   global message
   message = pypar.receive(source = pypar.mpiext.MPI_ANY_SOURCE)

if pypar.rank()==0 :    
   threading.Thread(target=communicator_thread).start()

   while message is None :
      print "Processing happens"
      time.sleep(1)
   print "Message is handled"

else :
   time.sleep(3.5)
   pypar.send("Hello",0)

What actually happens when running this with current version of pypar:

Message is handled

(program exits)

What happens with a GIL release, which I'm claiming is preferable:

Processing happens
Processing happens
Processing happens
Message is handled

(program exits)

What version of the product are you using? On what operating system?

pypar 2.1.4_94; python 2.6; Intel MPI; Linux

Please provide any additional information below.

A simple patch for this issue is as follows:

--- mpiext.c   2009-12-22 07:21:30.000000000 +0000
+++ mpiext.c    2010-10-24 14:17:14.000000000 +0100
@@ -211,8 +211,11 @@ static PyObject *receive_string(PyObject
   if (!PyArg_ParseTuple(args, "s#ii", &s, &length, &source, &tag))
     return NULL;

+  Py_BEGIN_ALLOW_THREADS;
   /* call the MPI routine */
   error = MPI_Recv(s, length, MPI_CHAR, source, tag, MPI_COMM_WORLD, &status);
+  Py_END_ALLOW_THREADS;

   if (error != 0) {
     MPI_Comm_rank(MPI_COMM_WORLD, &myid);    
@@ -468,9 +473,10 @@ static PyObject *receive_array(PyObject 
   if (!mpi_type) return NULL;  

   /* call the MPI routine */
+  Py_BEGIN_ALLOW_THREADS;
   error =  MPI_Recv(x->data, count, mpi_type, source, tag,
                    MPI_COMM_WORLD, &status);
-        
+  Py_END_ALLOW_THREADS;
   /* Do not DECREF x as it must be returned to Python */

   if (error != 0) {

Original issue reported on code.google.com by andrew.p...@gmail.com on 24 Oct 2010 at 4:01

GoogleCodeExporter commented 8 years ago
You are using blocking send and receive. MPI has non-blocking send and receives 
as well as part of the MPI specification. If you need this functionality, a 
simple option would be to extend pypar to include the non-blocking versions. I 
think this should be fairly straightforward as the skeleton is there.

Original comment by Ole.Moller.Nielsen@gmail.com on 28 Nov 2010 at 5:54

GoogleCodeExporter commented 8 years ago
I can see that having non-blocking MPI calls would also solve the problem, but 
I thought that the option to use a separate thread would be nice as well. Of 
course the example solution code I posted isn't quite thread-safe because it's 
writing straight into objects that another thread could be manipulating, but 
this problem can be worked around with a bit more care. (Such a problem will 
presumably arise with non-blocking MPI as well)?

Well, it's up to you in the end, I just thought I'd raise it as a potential 
useful enhancement.

Original comment by andrew.p...@gmail.com on 2 Dec 2010 at 4:32

GoogleCodeExporter commented 8 years ago
I'm just working on an extension to pypar to provide isend option.  

Original comment by Rowe.And...@gmail.com on 5 May 2011 at 3:39