We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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)
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gym/vector/utils/shared_memory.py`
Content:
```
1 import numpy as np
2 from multiprocessing import Array
3 from ctypes import c_bool
4 from collections import OrderedDict
5 
6 from gym import logger
7 from gym.spaces import Tuple, Dict
8 from gym.vector.utils.spaces import _BaseGymSpaces
9 
10 __all__ = [
11     'create_shared_memory',
12     'read_from_shared_memory',
13     'write_to_shared_memory'
14 ]
15 
16 def create_shared_memory(space, n=1):
17     """Create a shared memory object, to be shared across processes. This
18     eventually contains the observations from the vectorized environment.
19 
20     Parameters
21     ----------
22     space : `gym.spaces.Space` instance
23         Observation space of a single environment in the vectorized environment.
24 
25     n : int
26         Number of environments in the vectorized environment (i.e. the number
27         of processes).
28 
29     Returns
30     -------
31     shared_memory : dict, tuple, or `multiprocessing.Array` instance
32         Shared object across processes.
33     """
34     if isinstance(space, _BaseGymSpaces):
35         return create_base_shared_memory(space, n=n)
36     elif isinstance(space, Tuple):
37         return create_tuple_shared_memory(space, n=n)
38     elif isinstance(space, Dict):
39         return create_dict_shared_memory(space, n=n)
40     else:
41         raise NotImplementedError()
42 
43 def create_base_shared_memory(space, n=1):
44     dtype = space.dtype.char
45     if dtype in '?':
46         dtype = c_bool
47     return Array(dtype, n * int(np.prod(space.shape)))
48 
49 def create_tuple_shared_memory(space, n=1):
50     return tuple(create_shared_memory(subspace, n=n)
51         for subspace in space.spaces)
52 
53 def create_dict_shared_memory(space, n=1):
54     return OrderedDict([(key, create_shared_memory(subspace, n=n))
55         for (key, subspace) in space.spaces.items()])
56 
57 
58 def read_from_shared_memory(shared_memory, space, n=1):
59     """Read the batch of observations from shared memory as a numpy array.
60 
61     Parameters
62     ----------
63     shared_memory : dict, tuple, or `multiprocessing.Array` instance
64         Shared object across processes. This contains the observations from the
65         vectorized environment. This object is created with `create_shared_memory`.
66 
67     space : `gym.spaces.Space` instance
68         Observation space of a single environment in the vectorized environment.
69 
70     n : int
71         Number of environments in the vectorized environment (i.e. the number
72         of processes).
73 
74     Returns
75     -------
76     observations : dict, tuple or `np.ndarray` instance
77         Batch of observations as a (possibly nested) numpy array.
78 
79     Notes
80     -----
81     The numpy array objects returned by `read_from_shared_memory` shares the
82     memory of `shared_memory`. Any changes to `shared_memory` are forwarded
83     to `observations`, and vice-versa. To avoid any side-effect, use `np.copy`.
84     """
85     if isinstance(space, _BaseGymSpaces):
86         return read_base_from_shared_memory(shared_memory, space, n=n)
87     elif isinstance(space, Tuple):
88         return read_tuple_from_shared_memory(shared_memory, space, n=n)
89     elif isinstance(space, Dict):
90         return read_dict_from_shared_memory(shared_memory, space, n=n)
91     else:
92         raise NotImplementedError()
93 
94 def read_base_from_shared_memory(shared_memory, space, n=1):
95     return np.frombuffer(shared_memory.get_obj(),
96         dtype=space.dtype).reshape((n,) + space.shape)
97 
98 def read_tuple_from_shared_memory(shared_memory, space, n=1):
99     return tuple(read_from_shared_memory(memory, subspace, n=n)
100         for (memory, subspace) in zip(shared_memory, space.spaces))
101 
102 def read_dict_from_shared_memory(shared_memory, space, n=1):
103     return OrderedDict([(key, read_from_shared_memory(memory, subspace, n=n))
104         for ((key, memory), subspace) in zip(shared_memory.items(), 
105         space.spaces.values())])
106 
107 
108 def write_to_shared_memory(index, value, shared_memory, space):
109     """Write the observation of a single environment into shared memory.
110 
111     Parameters
112     ----------
113     index : int
114         Index of the environment (must be in `[0, num_envs)`).
115 
116     value : sample from `space`
117         Observation of the single environment to write to shared memory.
118 
119     shared_memory : dict, tuple, or `multiprocessing.Array` instance
120         Shared object across processes. This contains the observations from the
121         vectorized environment. This object is created with `create_shared_memory`.
122 
123     space : `gym.spaces.Space` instance
124         Observation space of a single environment in the vectorized environment.
125 
126     Returns
127     -------
128     `None`
129     """
130     if isinstance(space, _BaseGymSpaces):
131         write_base_to_shared_memory(index, value, shared_memory, space)
132     elif isinstance(space, Tuple):
133         write_tuple_to_shared_memory(index, value, shared_memory, space)
134     elif isinstance(space, Dict):
135         write_dict_to_shared_memory(index, value, shared_memory, space)
136     else:
137         raise NotImplementedError()
138 
139 def write_base_to_shared_memory(index, value, shared_memory, space):
140     size = int(np.prod(space.shape))
141     shared_memory[index * size:(index + 1) * size] = np.asarray(value,
142         dtype=space.dtype).flatten()
143 
144 def write_tuple_to_shared_memory(index, values, shared_memory, space):
145     for value, memory, subspace in zip(values, shared_memory, space.spaces):
146         write_to_shared_memory(index, value, memory, subspace)
147 
148 def write_dict_to_shared_memory(index, values, shared_memory, space):
149     for key, value in values.items():
150         write_to_shared_memory(index, value, shared_memory[key], space.spaces[key])
151
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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 @@
         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_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)

{"golden_diff": "diff --git a/gym/vector/utils/shared_memory.py b/gym/vector/utils/shared_memory.py\n--- a/gym/vector/utils/shared_memory.py\n+++ b/gym/vector/utils/shared_memory.py\n@@ -100,9 +100,8 @@\n         for (memory, subspace) in zip(shared_memory, space.spaces))\n \n def read_dict_from_shared_memory(shared_memory, space, n=1):\n-    return OrderedDict([(key, read_from_shared_memory(memory, subspace, n=n))\n-        for ((key, memory), subspace) in zip(shared_memory.items(), \n-        space.spaces.values())])\n+    return OrderedDict([(key, read_from_shared_memory(shared_memory[key],\n+        subspace, n=n)) for (key, subspace) in space.spaces.items()])\n \n \n def write_to_shared_memory(index, value, shared_memory, space):\n@@ -138,13 +137,14 @@\n \n def write_base_to_shared_memory(index, value, shared_memory, space):\n     size = int(np.prod(space.shape))\n-    shared_memory[index * size:(index + 1) * size] = np.asarray(value,\n-        dtype=space.dtype).flatten()\n+    destination = np.frombuffer(shared_memory.get_obj(), dtype=space.dtype)\n+    np.copyto(destination[index * size:(index + 1) * size], np.asarray(\n+        value, dtype=space.dtype).flatten())\n \n def write_tuple_to_shared_memory(index, values, shared_memory, space):\n     for value, memory, subspace in zip(values, shared_memory, space.spaces):\n         write_to_shared_memory(index, value, memory, subspace)\n \n def write_dict_to_shared_memory(index, values, shared_memory, space):\n-    for key, value in values.items():\n-        write_to_shared_memory(index, value, shared_memory[key], space.spaces[key])\n+    for key, subspace in space.spaces.items():\n+        write_to_shared_memory(index, values[key], shared_memory[key], subspace)\n", "issue": "VectorEnv seems much slower than SubprocVecEnv\nThe following test script shows a large performance difference between SubprocVecEnv and VectorEnv:\r\n\r\n```\r\nelapsed_vectorenv 24.20034408569336\r\nelapsed_subprocvecenv 0.813650369644165\r\n```\r\n\r\n```\r\nfrom gym.vector import make\r\nfrom baselines.common.vec_env import SubprocVecEnv\r\nimport numpy as np\r\nimport time\r\nimport gym\r\n\r\nNUM_STEPS = 1000\r\n\r\ndef run_vectorenv():\r\n    venv = make(\"PongNoFrameskip-v4\", num_envs=3)\r\n    venv.reset()\r\n    start = time.time()\r\n    for _ in range(NUM_STEPS):\r\n        obs, rews, dones, infos = venv.step(venv.action_space.sample())\r\n    elapsed = time.time() - start\r\n    venv.close()\r\n    return elapsed\r\n\r\n\r\ndef run_subprocvecenv():\r\n    def make_env():\r\n        return gym.make(\"PongNoFrameskip-v4\")\r\n\r\n    venv = SubprocVecEnv([make_env] * 3)\r\n    venv.reset()\r\n    start = time.time()\r\n    for _ in range(NUM_STEPS):\r\n        obs, rews, dones, infos = venv.step(np.array([venv.action_space.sample() for _ in range(venv.num_envs)]))\r\n    elapsed = time.time() - start\r\n    venv.close()\r\n    return elapsed\r\n\r\n\r\ndef main():\r\n    elapsed_vectorenv = run_vectorenv()\r\n    elapsed_subprocvecenv = run_subprocvecenv()\r\n    print(\"elapsed_vectorenv\", elapsed_vectorenv)\r\n    print(\"elapsed_subprocvecenv\", elapsed_subprocvecenv)\r\n```\n", "before_files": [{"content": "import numpy as np\nfrom multiprocessing import Array\nfrom ctypes import c_bool\nfrom collections import OrderedDict\n\nfrom gym import logger\nfrom gym.spaces import Tuple, Dict\nfrom gym.vector.utils.spaces import _BaseGymSpaces\n\n__all__ = [\n    'create_shared_memory',\n    'read_from_shared_memory',\n    'write_to_shared_memory'\n]\n\ndef create_shared_memory(space, n=1):\n    \"\"\"Create a shared memory object, to be shared across processes. This\n    eventually contains the observations from the vectorized environment.\n\n    Parameters\n    ----------\n    space : `gym.spaces.Space` instance\n        Observation space of a single environment in the vectorized environment.\n\n    n : int\n        Number of environments in the vectorized environment (i.e. the number\n        of processes).\n\n    Returns\n    -------\n    shared_memory : dict, tuple, or `multiprocessing.Array` instance\n        Shared object across processes.\n    \"\"\"\n    if isinstance(space, _BaseGymSpaces):\n        return create_base_shared_memory(space, n=n)\n    elif isinstance(space, Tuple):\n        return create_tuple_shared_memory(space, n=n)\n    elif isinstance(space, Dict):\n        return create_dict_shared_memory(space, n=n)\n    else:\n        raise NotImplementedError()\n\ndef create_base_shared_memory(space, n=1):\n    dtype = space.dtype.char\n    if dtype in '?':\n        dtype = c_bool\n    return Array(dtype, n * int(np.prod(space.shape)))\n\ndef create_tuple_shared_memory(space, n=1):\n    return tuple(create_shared_memory(subspace, n=n)\n        for subspace in space.spaces)\n\ndef create_dict_shared_memory(space, n=1):\n    return OrderedDict([(key, create_shared_memory(subspace, n=n))\n        for (key, subspace) in space.spaces.items()])\n\n\ndef read_from_shared_memory(shared_memory, space, n=1):\n    \"\"\"Read the batch of observations from shared memory as a numpy array.\n\n    Parameters\n    ----------\n    shared_memory : dict, tuple, or `multiprocessing.Array` instance\n        Shared object across processes. This contains the observations from the\n        vectorized environment. This object is created with `create_shared_memory`.\n\n    space : `gym.spaces.Space` instance\n        Observation space of a single environment in the vectorized environment.\n\n    n : int\n        Number of environments in the vectorized environment (i.e. the number\n        of processes).\n\n    Returns\n    -------\n    observations : dict, tuple or `np.ndarray` instance\n        Batch of observations as a (possibly nested) numpy array.\n\n    Notes\n    -----\n    The numpy array objects returned by `read_from_shared_memory` shares the\n    memory of `shared_memory`. Any changes to `shared_memory` are forwarded\n    to `observations`, and vice-versa. To avoid any side-effect, use `np.copy`.\n    \"\"\"\n    if isinstance(space, _BaseGymSpaces):\n        return read_base_from_shared_memory(shared_memory, space, n=n)\n    elif isinstance(space, Tuple):\n        return read_tuple_from_shared_memory(shared_memory, space, n=n)\n    elif isinstance(space, Dict):\n        return read_dict_from_shared_memory(shared_memory, space, n=n)\n    else:\n        raise NotImplementedError()\n\ndef read_base_from_shared_memory(shared_memory, space, n=1):\n    return np.frombuffer(shared_memory.get_obj(),\n        dtype=space.dtype).reshape((n,) + space.shape)\n\ndef read_tuple_from_shared_memory(shared_memory, space, n=1):\n    return tuple(read_from_shared_memory(memory, subspace, n=n)\n        for (memory, subspace) in zip(shared_memory, space.spaces))\n\ndef read_dict_from_shared_memory(shared_memory, space, n=1):\n    return OrderedDict([(key, read_from_shared_memory(memory, subspace, n=n))\n        for ((key, memory), subspace) in zip(shared_memory.items(), \n        space.spaces.values())])\n\n\ndef write_to_shared_memory(index, value, shared_memory, space):\n    \"\"\"Write the observation of a single environment into shared memory.\n\n    Parameters\n    ----------\n    index : int\n        Index of the environment (must be in `[0, num_envs)`).\n\n    value : sample from `space`\n        Observation of the single environment to write to shared memory.\n\n    shared_memory : dict, tuple, or `multiprocessing.Array` instance\n        Shared object across processes. This contains the observations from the\n        vectorized environment. This object is created with `create_shared_memory`.\n\n    space : `gym.spaces.Space` instance\n        Observation space of a single environment in the vectorized environment.\n\n    Returns\n    -------\n    `None`\n    \"\"\"\n    if isinstance(space, _BaseGymSpaces):\n        write_base_to_shared_memory(index, value, shared_memory, space)\n    elif isinstance(space, Tuple):\n        write_tuple_to_shared_memory(index, value, shared_memory, space)\n    elif isinstance(space, Dict):\n        write_dict_to_shared_memory(index, value, shared_memory, space)\n    else:\n        raise NotImplementedError()\n\ndef write_base_to_shared_memory(index, value, shared_memory, space):\n    size = int(np.prod(space.shape))\n    shared_memory[index * size:(index + 1) * size] = np.asarray(value,\n        dtype=space.dtype).flatten()\n\ndef write_tuple_to_shared_memory(index, values, shared_memory, space):\n    for value, memory, subspace in zip(values, shared_memory, space.spaces):\n        write_to_shared_memory(index, value, memory, subspace)\n\ndef write_dict_to_shared_memory(index, values, shared_memory, space):\n    for key, value in values.items():\n        write_to_shared_memory(index, value, shared_memory[key], space.spaces[key])\n", "path": "gym/vector/utils/shared_memory.py"}], "after_files": [{"content": "import numpy as np\nfrom multiprocessing import Array\nfrom ctypes import c_bool\nfrom collections import OrderedDict\n\nfrom gym import logger\nfrom gym.spaces import Tuple, Dict\nfrom gym.vector.utils.spaces import _BaseGymSpaces\n\n__all__ = [\n    'create_shared_memory',\n    'read_from_shared_memory',\n    'write_to_shared_memory'\n]\n\ndef create_shared_memory(space, n=1):\n    \"\"\"Create a shared memory object, to be shared across processes. This\n    eventually contains the observations from the vectorized environment.\n\n    Parameters\n    ----------\n    space : `gym.spaces.Space` instance\n        Observation space of a single environment in the vectorized environment.\n\n    n : int\n        Number of environments in the vectorized environment (i.e. the number\n        of processes).\n\n    Returns\n    -------\n    shared_memory : dict, tuple, or `multiprocessing.Array` instance\n        Shared object across processes.\n    \"\"\"\n    if isinstance(space, _BaseGymSpaces):\n        return create_base_shared_memory(space, n=n)\n    elif isinstance(space, Tuple):\n        return create_tuple_shared_memory(space, n=n)\n    elif isinstance(space, Dict):\n        return create_dict_shared_memory(space, n=n)\n    else:\n        raise NotImplementedError()\n\ndef create_base_shared_memory(space, n=1):\n    dtype = space.dtype.char\n    if dtype in '?':\n        dtype = c_bool\n    return Array(dtype, n * int(np.prod(space.shape)))\n\ndef create_tuple_shared_memory(space, n=1):\n    return tuple(create_shared_memory(subspace, n=n)\n        for subspace in space.spaces)\n\ndef create_dict_shared_memory(space, n=1):\n    return OrderedDict([(key, create_shared_memory(subspace, n=n))\n        for (key, subspace) in space.spaces.items()])\n\n\ndef read_from_shared_memory(shared_memory, space, n=1):\n    \"\"\"Read the batch of observations from shared memory as a numpy array.\n\n    Parameters\n    ----------\n    shared_memory : dict, tuple, or `multiprocessing.Array` instance\n        Shared object across processes. This contains the observations from the\n        vectorized environment. This object is created with `create_shared_memory`.\n\n    space : `gym.spaces.Space` instance\n        Observation space of a single environment in the vectorized environment.\n\n    n : int\n        Number of environments in the vectorized environment (i.e. the number\n        of processes).\n\n    Returns\n    -------\n    observations : dict, tuple or `np.ndarray` instance\n        Batch of observations as a (possibly nested) numpy array.\n\n    Notes\n    -----\n    The numpy array objects returned by `read_from_shared_memory` shares the\n    memory of `shared_memory`. Any changes to `shared_memory` are forwarded\n    to `observations`, and vice-versa. To avoid any side-effect, use `np.copy`.\n    \"\"\"\n    if isinstance(space, _BaseGymSpaces):\n        return read_base_from_shared_memory(shared_memory, space, n=n)\n    elif isinstance(space, Tuple):\n        return read_tuple_from_shared_memory(shared_memory, space, n=n)\n    elif isinstance(space, Dict):\n        return read_dict_from_shared_memory(shared_memory, space, n=n)\n    else:\n        raise NotImplementedError()\n\ndef read_base_from_shared_memory(shared_memory, space, n=1):\n    return np.frombuffer(shared_memory.get_obj(),\n        dtype=space.dtype).reshape((n,) + space.shape)\n\ndef read_tuple_from_shared_memory(shared_memory, space, n=1):\n    return tuple(read_from_shared_memory(memory, subspace, n=n)\n        for (memory, subspace) in zip(shared_memory, space.spaces))\n\ndef read_dict_from_shared_memory(shared_memory, space, n=1):\n    return OrderedDict([(key, read_from_shared_memory(shared_memory[key],\n        subspace, n=n)) for (key, subspace) in space.spaces.items()])\n\n\ndef write_to_shared_memory(index, value, shared_memory, space):\n    \"\"\"Write the observation of a single environment into shared memory.\n\n    Parameters\n    ----------\n    index : int\n        Index of the environment (must be in `[0, num_envs)`).\n\n    value : sample from `space`\n        Observation of the single environment to write to shared memory.\n\n    shared_memory : dict, tuple, or `multiprocessing.Array` instance\n        Shared object across processes. This contains the observations from the\n        vectorized environment. This object is created with `create_shared_memory`.\n\n    space : `gym.spaces.Space` instance\n        Observation space of a single environment in the vectorized environment.\n\n    Returns\n    -------\n    `None`\n    \"\"\"\n    if isinstance(space, _BaseGymSpaces):\n        write_base_to_shared_memory(index, value, shared_memory, space)\n    elif isinstance(space, Tuple):\n        write_tuple_to_shared_memory(index, value, shared_memory, space)\n    elif isinstance(space, Dict):\n        write_dict_to_shared_memory(index, value, shared_memory, space)\n    else:\n        raise NotImplementedError()\n\ndef write_base_to_shared_memory(index, value, shared_memory, space):\n    size = int(np.prod(space.shape))\n    destination = np.frombuffer(shared_memory.get_obj(), dtype=space.dtype)\n    np.copyto(destination[index * size:(index + 1) * size], np.asarray(\n        value, dtype=space.dtype).flatten())\n\ndef write_tuple_to_shared_memory(index, values, shared_memory, space):\n    for value, memory, subspace in zip(values, shared_memory, space.spaces):\n        write_to_shared_memory(index, value, memory, subspace)\n\ndef write_dict_to_shared_memory(index, values, shared_memory, space):\n    for key, subspace in space.spaces.items():\n        write_to_shared_memory(index, values[key], shared_memory[key], subspace)\n", "path": "gym/vector/utils/shared_memory.py"}]}