code: def run(self):
      drv.init()
      a0 = numpy.zeros((p,), dtype=numpy.complex64)
      self.dev = drv.Device(self.number)
      self.ctx = self.dev.make_context()
      # TO VERIFY WHETHER ALL THE MEMORY IS FREED BEFORE NEXT ALLOCATION (THIS DOES NOT HAPPEN IN MULTITHREADING)
      print(drv.mem_get_info())
      self.gpu_a = garray.empty(
          (self.input_cpu.size,), dtype=numpy.complex64
      )
      self.gpu_b = garray.zeros_like(self.gpu_a)
      self.gpu_a = garray.to_gpu(self.input_cpu)
      plan = Plan(a0.shape, context=self.ctx)
      plan.execute(self.gpu_a, self.gpu_b, batch=p / m)
      self.temp = self.gpu_b.get()
      self.output_cpu.put(self.temp)
      self.output_cpu.close()
      self.ctx.pop()
      del self.gpu_
      del self.gpu_b
      del self.ctx
  
      print("till the end %d" % self.number)
  
file_path: pycuda/examples/from-wiki/2d_fft.py
imports: import numpy
  import scipy.misc
  import numpy.fft
  import multiprocessing
  from pyfft.cuda import Plan
  from pycuda.tools import make_default_context
  import pycuda.tools
  import pycuda.gpuarray
  import pycuda.driver
label_desc: Use image node_id 2 for calling the GPUMulti obj's underlying member method code with example usage: obj.run() without return types