question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

VectorEnv/ThreadedVectorEnv have worse performance than Env

See original GitHub issue

❓ Questions and Help

Hi,

I wrote the following script to compare the performance of different types of habitat Envs.

I expected the vectorised environments to run faster than the normal Env, however got the following results:

Normal Env took 299.7s to take 500 steps in 14 environments
VectorEnv took 484.4s to take 500 steps in 14 environments
ThreadedVectorEnv took 2345.4s to take 500 steps in 14 environments

Can anyone explain this result please?

BTW: This was run on an RTX 2080Ti GPU.

"""
example.py
==================================================
This is an example of how to use the habitat environment class.
"""

import habitat
from habitat_baselines.utils.env_utils import (
    make_env_fn,
    construct_envs,
    construct_threaded_envs,
)
from habitat_baselines.config.default import get_config


def example():
    """
    Initialises a `habitat.Env` environment, then takes random steps.
    """

    baseline_config = get_config("configs/tasks/pointnav.yaml")
    config = habitat.get_config("configs/tasks/pointnav.yaml")

    config.defrost()
    config.TASK_CONFIG = baseline_config.TASK_CONFIG
    config.freeze()

    env_class = habitat.Env

    env = make_env_fn(config, env_class)

    n_steps = 500
    n_episodes = env.number_of_episodes

    for episode in range(n_steps):
        count_steps = 0
        _ = env.reset()

        scene_name = env.current_episode.scene_id.split(sep="/")[-1].strip(".glb")
        print(f"\nStarting episode {episode+1}/{n_episodes} in {scene_name}...")

        print("Stepping around...")
        for step in range(n_steps):
            action = env.action_space.sample()

            while action["action"] == "STOP":
                action = env.action_space.sample()

            _ = env.step(action)
            count_steps += 1

        print(
            f"Episode {episode+1} in scene {scene_name} finished after {count_steps} steps."
        )


def vector_example():
    """
    Initialises a `habitat.VectorEnv` environment, then takes random steps.
    """

    baseline_config = get_config("configs/tasks/pointnav.yaml")
    config = habitat.get_config("configs/tasks/pointnav.yaml")

    config.defrost()
    config.TASK_CONFIG = baseline_config.TASK_CONFIG
    config.NUM_ENVIRONMENTS = 14
    config.SENSORS = baseline_config.SENSORS
    config.SIMULATOR_GPU_ID = 0
    config.freeze()

    env_class = habitat.Env
    envs = construct_envs(config, env_class)

    _ = envs.reset()

    n_steps = 500
    n_envs = envs.num_envs
    n_episodes = envs.number_of_episodes[0]

    for episode in range(n_episodes):
        count_steps = 0
        print(
            f"Starting episode {episode}/{n_episodes} in parallel processes across {n_envs} environments."
        )
        scene_names = [
            ep.scene_id.split("/")[-1].strip(".glb") for ep in envs.current_episodes()
        ]

        for i, scene in enumerate(scene_names):
            print(f"Stepping around in Environment {i+1}: {scene}..")

        for step in range(n_steps):
            random_actions = [
                action_space.sample() for action_space in envs.action_spaces
            ]
            _ = envs.step(random_actions)
            count_steps += 1

        print("Episodes finished after {} steps.".format(count_steps))


def threaded_vector_example():
    """
    Initialises a `habitat.ThreadedVectorEnv` environment, then takes random steps.
    """

    baseline_config = get_config("configs/tasks/pointnav.yaml")
    config = habitat.get_config("configs/tasks/pointnav.yaml")

    config.defrost()
    config.TASK_CONFIG = baseline_config.TASK_CONFIG
    config.NUM_ENVIRONMENTS = 14
    config.SENSORS = baseline_config.SENSORS
    config.SIMULATOR_GPU_ID = 0
    config.freeze()

    env_class = habitat.Env

    envs = construct_threaded_envs(config, env_class)

    _ = envs.reset()

    n_steps = 500
    n_envs = envs.num_envs
    n_episodes = envs.number_of_episodes[0]

    for episode in range(n_episodes):
        count_steps = 0
        print(
            f"Starting episode {episode}/{n_episodes} in parallel threads across {n_envs} environments."
        )
        scene_names = [
            ep.scene_id.split("/")[-1].strip(".glb") for ep in envs.current_episodes()
        ]

        for i, scene in enumerate(scene_names):
            print(f"Stepping around in Environment {i+1}: {scene}..")

        for step in range(n_steps):
            random_actions = [
                action_space.sample() for action_space in envs.action_spaces
            ]
            _ = envs.step(random_actions)
            count_steps += 1

        print("Episodes finished after {} steps.".format(count_steps))


if __name__ == "__main__":
    import time

    start = time.time()
    example()
    end = time.time()
    example_time = end - start

    start = time.time()
    vector_example()
    end = time.time()
    vector_example_time = end - start

    start = time.time()
    threaded_vector_example()
    end = time.time()
    threaded_example_time = end - start

    print(
        f"\n\n\nNormal Env took {round(example_time, 1)}s to take 500 steps in 14 Environments"
    )
    print(
        f"VectorEnv took {round(vector_example_time, 1)}s to take 500 steps in 14 Environments"
    )
    print(
        f"ThreadedVectorEnv took {round(threaded_example_time, 1)}s to take 500 steps in 14 Environments"
    )

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
erikwijmanscommented, Feb 22, 2021

Also, I’ll clarify that ThreadedVectorEnv is not actually parallel (it uses python threads). That exists solely for debugging purposes and it being slow is a (necessary, albeit unfortunate) side effect of it fulfilling that role. It is not intended for use when performance matters.

0reactions
rpartseycommented, Sep 5, 2022

Closing the issue because it has not had recent activity.

Read more comments on GitHub >

github_iconTop Results From Across the Web

SubprocVecEnv performance compared to gym.vector ...
Hi, I'm trying to use SubProcVecEnv to create a vectorized environment and use it in my own PPO implementation. I have a couple...
Read more >
Should I prefer array over vector for performance? [duplicate]
No. (to satisfy the comment pedants, no, you should not "prefer" arrays over vectors for performance, but sure, you should "consider" using ...
Read more >
Java 18: Vector API — Do we get free speed-up? - Medium
The performance speed-up results from applying the same operation on more than one “piece of data” within one CPU cycle. As a simple...
Read more >
Top 20 C++ multithreading mistakes and how to avoid them
Mistake # 1: Not using join() to wait for background threads before terminating an application. If we forgot to join a thread or...
Read more >
Configuration Handling — Flask Documentation (1.1.x)
The ENV and DEBUG config values are special because they may behave inconsistently if changed after the app has begun setting up. In...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found