Repository: openai/gym

Issue:
VectorEnv seems much slower than SubprocVecEnv
The following test script shows a large performance difference between SubprocVecEnv and VectorEnv:

```
elapsed_vectorenv 24.20034408569336
elapsed_subprocvecenv 0.813650369644165
```

```
from gym.vector import make
from baselines.common.vec_env import SubprocVecEnv
import numpy as np
import time
import gym

NUM_STEPS = 1000

def run_vectorenv():
    venv = make("PongNoFrameskip-v4", num_envs=3)
    venv.reset()
    start = time.time()
    for _ in range(NUM_STEPS):
        obs, rews, dones, infos = venv.step(venv.action_space.sample())
    elapsed = time.time() - start
    venv.close()
    return elapsed


def run_subprocvecenv():
    def make_env():
        return gym.make("PongNoFrameskip-v4")

    venv = SubprocVecEnv([make_env] * 3)
    venv.reset()
    start = time.time()
    for _ in range(NUM_STEPS):
        obs, rews, dones, infos = venv.step(np.array([venv.action_space.sample() for _ in range(venv.num_envs)]))
    elapsed = time.time() - start
    venv.close()
    return elapsed


def main():
    elapsed_vectorenv = run_vectorenv()
    elapsed_subprocvecenv = run_subprocvecenv()
    print("elapsed_vectorenv", elapsed_vectorenv)
    print("elapsed_subprocvecenv", elapsed_subprocvecenv)
```


Discussion:

Resolving patch:
diff --git a/gym/vector/utils/shared_memory.py b/gym/vector/utils/shared_memory.py
--- a/gym/vector/utils/shared_memory.py
+++ b/gym/vector/utils/shared_memory.py
@@ -100,9 +100,8 @@ def read_tuple_from_shared_memory(shared_memory, space, n=1):
         for (memory, subspace) in zip(shared_memory, space.spaces))
 
 def read_dict_from_shared_memory(shared_memory, space, n=1):
-    return OrderedDict([(key, read_from_shared_memory(memory, subspace, n=n))
-        for ((key, memory), subspace) in zip(shared_memory.items(), 
-        space.spaces.values())])
+    return OrderedDict([(key, read_from_shared_memory(shared_memory[key],
+        subspace, n=n)) for (key, subspace) in space.spaces.items()])
 
 
 def write_to_shared_memory(index, value, shared_memory, space):
@@ -138,13 +137,14 @@ def write_to_shared_memory(index, value, shared_memory, space):
 
 def write_base_to_shared_memory(index, value, shared_memory, space):
     size = int(np.prod(space.shape))
-    shared_memory[index * size:(index + 1) * size] = np.asarray(value,
-        dtype=space.dtype).flatten()
+    destination = np.frombuffer(shared_memory.get_obj(), dtype=space.dtype)
+    np.copyto(destination[index * size:(index + 1) * size], np.asarray(
+        value, dtype=space.dtype).flatten())
 
 def write_tuple_to_shared_memory(index, values, shared_memory, space):
     for value, memory, subspace in zip(values, shared_memory, space.spaces):
         write_to_shared_memory(index, value, memory, subspace)
 
 def write_dict_to_shared_memory(index, values, shared_memory, space):
-    for key, value in values.items():
-        write_to_shared_memory(index, value, shared_memory[key], space.spaces[key])
+    for key, subspace in space.spaces.items():
+        write_to_shared_memory(index, values[key], shared_memory[key], subspace)


Test patch: