minerllabs / minerl

MineRL Competition for Sample Efficient Reinforcement Learning - Python Package
http://minerl.io/docs/
Other
672 stars 153 forks source link

Unable to reset environments asynchronously #214

Open jon-chuang opened 5 years ago

jon-chuang commented 5 years ago

When I run environments in parallel, only one of them gets reset while the rest wait for the first to be reset again.

This can be recreated with the following test script:

import gym
import minerl
from multiprocessing import Pipe, Process
import multiprocessing
import logging
​
def worker(remote, env_name):
    name = multiprocessing.current_process().name
    print("[{}]".format(name)) + "Setting up Minecraft Environment...")
    env = gym.make(env_name)
    remote.send("[{}]".format(name) + "Minecraft running.")
    while True:
        cmd, action = remote.recv()
        if cmd == 'reset':
            print("[{}]".format(name) + "Resetting...")
            try:
                obs, info = env.reset()
            except:
                print("[{}]".format(name) + "Reset failed. Restarting the Minecraft environment...")
                env = gym.make()
                obs, info = env.reset()
            print("[{}]".format(name) + "Ready.")
            remote.send((obs, info))
​
        elif cmd == 'step':
            obs, reward, done, info = env.step(action)
            if done:
                obs = env.reset()
            remote.send((obs, reward, done, info))
​
        elif cmd == 'render':
            remote.send(env.render())
​
        elif cmd == 'close':
            env.close()
            remote.close()
            break

class GymManager():
    def __init__(self, env):
        logger = multiprocessing.log_to_stderr()
        logger.setLevel(logging.DEBUG)  
        self.active_remote, a = Pipe()
        self.backup_remote, b = Pipe()
        self.active_env = Process(target=worker, args=(a, env))
        self.backup_env = Process(target=worker, args=(b, env))
        self.active_env.start()
        self.backup_env.start()
        print(self.backup_remote.recv())
        self.backup_remote.send(('reset', 0))
        print("Reset signal sent...")
        print(self.active_remote.recv())

    def render(self):
        self.active_remote.send(('render', 0))
        return self.active_remote.recv()

    def step(self, action):
        self.active_remote.send(('step', action))
        return self.active_remote.recv()

    def reset(self):
        self.active_remote.send(('reset',0))

        temp = self.backup_env
        self.backup_env = self.active_env
        self.active_env = temp

        temp = self.backup_remote
        self.backup_remote = self.active_remote
        self.active_remote = temp

        return self.active_remote.recv()

    def close(self):
        self.active_remote.send('close', 0)
        return True
MadcowD commented 4 years ago

This looks like an important issue to fix. I will have a go at it.

balloch commented 4 years ago

any updates on this?

will-maclean commented 1 year ago

Any updates?

Miffyli commented 1 year ago

@will-maclean No updates on this. MineRL has since this update gone through big changes (e.g., the current v1.0 is a completely different code-base). Generally though, you should be able to asynch reset environments as long they live in separate process and do not depend on each other (but I have not tried this).