def _setup_gpu(self, agents, evals, learner, gpus):
        """
            Assigns GPU to agents and learners in an optimal way.
            No GPU, do nothing
        """
        actors = agents + evals
        if gpus == "auto":
            if 'CUDA_VISIBLE_DEVICES' in os.environ:
                gpus = os.environ['CUDA_VISIBLE_DEVICES']
            else:
                gpus = ''
        gpus_str = gpus
        try:
            gpus = [x for x in gpus_str.split(',') if len(x) > 0]
        except Exception as e:
            print("Error parsing GPU specification {}\n".format(gpus_str),
                  file=sys.stderr)
            raise e
        if len(gpus) == 0:
            print('Using CPU')
        elif len(gpus) == 1:
            gpu = gpus[0]
            print('Putting agents, evals and learner on GPU {}'.format(gpu))
            for actor in actors + [learner]:
                actor.set_envs({'CUDA_VISIBLE_DEVICES': gpu})
        elif len(gpus) > 1:
            learner_gpu = gpus[0]
            print('Putting learner on GPU {}'.format(learner_gpu))
            learner.set_envs({'CUDA_VISIBLE_DEVICES': learner_gpu})

            actors_per_gpu = float(len(actors)) / (len(gpus) - 1)
            actors_per_gpu = int(math.ceil(actors_per_gpu))
            print('Putting up to {} agents/evals on each of gpus {}'.format(
                    actors_per_gpu, ','.join([x for x in gpus[1:]])))

            for i, actor in enumerate(actors):
                cur_gpu = gpus[1 + i // actors_per_gpu]
                actor.set_envs({'CUDA_VISIBLE_DEVICES': cur_gpu})

            Assigns GPU to agents and learners in an optimal way.
            No GPU, do nothing
        
surreal/subproc/surreal_subproc.py