FWIW, that looks something like this:

```patch
diff --git a/python/firedrake/core_types.pyx b/python/firedrake/core_types.pyx
index 37965f2..f07d1e3 100644
--- a/python/firedrake/core_types.pyx
+++ b/python/firedrake/core_types.pyx
@@ -1105,17 +1105,36 @@ class Halo(object):
                 remote_sends[rank].append(index)
 
         # Propagate remote send lists to the actual sender
-        for p in range(self.comm.size):
-            if p == self.comm.rank: continue
-            if remote_sends.has_key(p):
-                send_buf = np.array(remote_sends[p], dtype=np.int32)
-                self.comm.send(send_buf, dest=p, tag=self.tag)
-
-        for p in range(self.comm.size):
-            if p == self.comm.rank: continue
-            local_sends = self.comm.recv(source=p, tag=self.tag)
-            if len(local_sends) > 0:
-                self._sends[p] = list(local_sends)
+        send_reqs = []
+        for p in remote_sends:
+            # send sizes
+            s = np.array(len(remote_sends[p]), dtype=np.int32)
+            send_reqs.append(self.comm.Isend(s, dest=p, tag=self.tag))
+
+        recv_reqs = []
+        sizes = [np.empty(1, dtype=np.int32) for _ in range(len(self._receives))]
+        for i, p in enumerate(self._receives):
+            # receive sizes
+            recv_reqs.append(self.comm.Irecv(sizes[i], source=p, tag=self.tag))
+
+        MPI.Request.Waitall(recv_reqs)
+        MPI.Request.Waitall(send_reqs)
+        
+        for i, p in enumerate(self._receives):
+            # allocate buffers
+            self._sends[p] = np.empty(sizes[i], dtype=np.int32)
+
+        send_reqs = []
+        for p in remote_sends:
+            send_buf = np.array(remote_sends[p], dtype=np.int32)
+            send_reqs.append(self.comm.Isend(send_buf, dest=p, tag=self.tag))
+
+        recv_reqs = []
+        for p in self._receives:
+            recv_reqs.append(self.comm.Irecv(self._sends[p], source=p, tag=self.tag))
+
+        MPI.Request.Waitall(send_reqs)
+        MPI.Request.Waitall(recv_reqs)
 
         """PETSc's LGMap cannot be used here directly, because:
         1) DMGetLocalToGlobalMapping assumes that the local section
```

Only very lightly tested, there may be a better way.