From 16c2d3bfffb15a8a52ba17f4512569fec8038d26 Mon Sep 17 00:00:00 2001
From: zachjweiner <zachjweiner@gmail.com>
Date: Mon, 26 Aug 2019 15:16:59 -0500
Subject: [PATCH] adds get_async and doc, untested

---
 pyopencl/array.py | 76 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 58 insertions(+), 18 deletions(-)

diff --git a/pyopencl/array.py b/pyopencl/array.py
index 24c6ded6..7fc8c833 100644
--- a/pyopencl/array.py
+++ b/pyopencl/array.py
@@ -305,6 +305,7 @@ class Array(object):
     .. attribute :: T
     .. automethod :: set
     .. automethod :: get
+    .. automethod :: get_async
     .. automethod :: copy
 
     .. automethod :: __str__
@@ -375,6 +376,12 @@ class Array(object):
     care of its own operation ordering. The facilities in this section make
     this possible.
 
+    .. note::
+
+        Currently, read and write events are not distinguished.
+        As a result, e.g., read-only operations will needlessly wait on other
+        read-only operations (i.e., executed among asynchronous queues).
+
     .. versionadded:: 2014.1.1
 
     .. attribute:: events
@@ -627,23 +634,7 @@ class Array(object):
                     is_blocking=not async_)
             self.add_event(event1)
 
-    def get(self, queue=None, ary=None, async_=None, **kwargs):
-        """Transfer the contents of *self* into *ary* or a newly allocated
-        :mod:`numpy.ndarray`. If *ary* is given, it must have the same
-        shape and dtype.
-
-        .. versionchanged:: 2015.2
-
-            *ary* with different shape was deprecated.
-
-        .. versionchanged:: 2017.2.1
-
-            Python 3.7 makes ``async`` a reserved keyword. On older Pythons,
-            we will continue to  accept *async* as a parameter, however this
-            should be considered deprecated. *async_* is the new, official
-            spelling.
-        """
-
+    def _get(self, queue=None, ary=None, async_=None, **kwargs):
         # {{{ handle 'async' deprecation
 
         async_arg = kwargs.pop("async", None)
@@ -688,12 +679,61 @@ class Array(object):
                     "to associate one.")
 
         if self.size:
-            cl.enqueue_copy(queue, ary, self.base_data,
+            event1 = cl.enqueue_copy(queue, ary, self.base_data,
                     device_offset=self.offset,
                     wait_for=self.events, is_blocking=not async_)
+            self.add_event(event1)
+        else:
+            event1 = None
+
+        return ary, event1
+
+    def get(self, queue=None, ary=None, async_=None, **kwargs):
+        """Transfer the contents of *self* into *ary* or a newly allocated
+        :mod:`numpy.ndarray`. If *ary* is given, it must have the same
+        shape and dtype.
+
+        .. versionchanged:: 2019.1
+
+            Calling with `async_=True` was deprecated and replaced by
+            :meth:`get_async`.
+            The event returned by :meth:`pyopencl.enqueue_copy` is now stored into
+            :attr:`events` to ensure data is not modified before the copy is
+            complete.
+
+        .. versionchanged:: 2015.2
+
+            *ary* with different shape was deprecated.
+
+        .. versionchanged:: 2017.2.1
+
+            Python 3.7 makes ``async`` a reserved keyword. On older Pythons,
+            we will continue to  accept *async* as a parameter, however this
+            should be considered deprecated. *async_* is the new, official
+            spelling.
+        """
+
+        if async_:
+            from warnings import warn
+            warn("calling pyopencl.Array.get with `async_=True` is deprecated. "
+                    "Please use pyopencl.Array.get_async for asynchronous "
+                    "device-to-host transfers",
+                    DeprecationWarning, 2)
+
+        ary, event1 = self.get(queue=queue, ary=ary, async_=async_, **kwargs)
 
         return ary
 
+    def get_async(self, queue=None, ary=None, **kwargs):
+        """
+        Asynchronous version of :meth:`get`, following the same calling convention
+        while returning a tuple ``(ary, event)`` containing the host array `ary`
+        and the :class:`pyopencl.NannyEvent` `event` returned by
+        :meth:`pyopencl.enqueue_copy`.
+        """
+
+        return self.get(queue=queue, ary=ary, async_=True, **kwargs)
+
     def copy(self, queue=_copy_queue):
         """
         :arg queue: The :class:`CommandQueue` for the returned array.
-- 
GitLab