class_docstr: Interface to handle asynchronous data transfer using double buffering.
  
  An asynchronous data transfer is initiated by :meth:`put`, and the result,
  the array transferred to a target device, is obtained by :meth:`get`.
  You should call :meth:`put` followed by :meth:`get`.
  
  Args:
      device (int): Device ID to which an array is sent. Negative value
          indicates the host memory (CPU). If it is omitted, the array is
          left in the original device. Asynchronous data transfer is used
          only when device ID >= 0.
      stream (cupy.cuda.Stream): CUDA stream. An array is sent to GPU
          asynchronously using this stream. If ``None``, asynchronous data
          transfer is not used.
class_docstr_tok: ["Interface","to","handle","asynchronous","data","transfer","using","double","buffering",".","An","asynchronous","data","transfer","is","initiated","by",":","meth",":","`","put","`",",","and","the","result",",","the","array","transferred","to","a","target","device",",","is","obtained","by",":","meth",":","`","get","`",".","You","should","call",":","meth",":","`","put","`","followed","by",":","meth",":","`","get","`",".","Args",":","device","(","int",")",":","Device","ID","to","which","an","array","is","sent",".","Negative","value","indicates","the","host","memory","(","CPU",")",".","If","it","is","omitted",",","the","array","is","left","in","the","original","device",".","Asynchronous","data","transfer","is","used","only","when","device","ID",">","=","0.","stream","(","cupy.cuda.Stream",")",":","CUDA","stream",".","An","array","is","sent","to","GPU","asynchronously","using","this","stream",".","If","``","None","``",",","asynchronous","data","transfer","is","not","used","."]
docstr: Initiates asynchronous transfer of an array to a target device.
  
  This method assumes that the input array is a numpy array and
  on host memory without page-locked. So, it first copies the data
  to page-locked host memory (so called pinned memory), then initiates
  asynchronous data transfer to a target device.
  
  The intermediate arrays on pinned memory and cupy arrays on the
  target device are retained at self._array_set in order to reduce number
  of memory allocation/release, and they are to be reused for subsequent
  data transfer as long as the size are the same.
  
  Double buffering scheme is used here, so you can initiate next data
  transfer safely even when current data is still used on the target
  device.
docstr_tok: ["Initiates","asynchronous","transfer","of","an","array","to","a","target","device",".","This","method","assumes","that","the","input","array","is","a","numpy","array","and","on","host","memory","without","page-locked",".","So",",","it","first","copies","the","data","to","page-locked","host","memory","(","so","called","pinned","memory",")",",","then","initiates","asynchronous","data","transfer","to","a","target","device",".","The","intermediate","arrays","on","pinned","memory","and","cupy","arrays","on","the","target","device","are","retained","at","self._array_set","in","order","to","reduce","number","of","memory","allocation\/release",",","and","they","are","to","be","reused","for","subsequent","data","transfer","as","long","as","the","size","are","the","same",".","Double","buffering","scheme","is","used","here",",","so","you","can","initiate","next","data","transfer","safely","even","when","current","data","is","still","used","on","the","target","device","."]
code: def put(self, array):
      """Initiates asynchronous transfer of an array to a target device.
  
      This method assumes that the input array is a numpy array and
      on host memory without page-locked. So, it first copies the data
      to page-locked host memory (so called pinned memory), then initiates
      asynchronous data transfer to a target device.
  
      The intermediate arrays on pinned memory and cupy arrays on the
      target device are retained at self._array_set in order to reduce number
      of memory allocation/release, and they are to be reused for subsequent
      data transfer as long as the size are the same.
  
      Double buffering scheme is used here, so you can initiate next data
      transfer safely even when current data is still used on the target
      device.
      """
      if (
          self._device is None
          or self._device < 0
          or self._stream is None
      ):
          self._ret_array.append(to_device(self._device, array))
          return
  
      pin_array, cp_array = self._array_set.pop(0)
      if pin_array is not None:
          if pin_array.nbytes != array.nbytes:
              pin_array = None
  
      with cuda.get_device_from_id(self._device):
          if pin_array is None:
              # The global synchronization below is necessary to ensure ALL
              # operations including compute and data transfer submitted
              # to GPU so far have been completed, in order to avoid possible
              # memory corruption due to race condition among operations that
              # use different CUDA streams.
              # You can also solve this sort of race condition by preparing a
              # memory pool for each CUDA stream and using it carefully.
              cuda.cupy.cuda.runtime.deviceSynchronize()
              pin_mem = cuda.cupy.cuda.alloc_pinned_memory(array.nbytes)
              pin_array = numpy.frombuffer(
                  pin_mem, array.dtype, array.size
              ).reshape(array.shape)
              cp_array = cuda.cupy.empty(array.shape, array.dtype)
  
          pin_array[...] = array  # copy(CPU): paged -> pinned
          cp_array.set(pin_array, self._stream)  # copy: CPU to GPU
  
      self._array_set.append([pin_array, cp_array])
      self._ret_array.append(cp_array)
  
imports: import collections
  import numpy
  import six
  import chainer
  from chainer import backend
  from chainer.backends import cuda
label_desc: Use image node_id 2 for calling the Conveyor obj's underlying member method code with example usage: obj.put(array) without return types