### Summary

Within `AnsibleModule.run_command()`, prior to calling `subprocess.Popen`, it uses `os.environ.get()` to read some environment variables:

https://github.com/ansible/ansible/blob/v2.11.0/lib/ansible/module_utils/basic.py#L1947

After the `Popen` call, it deletes some environment variables that were added using `del os.environ[]`:

https://github.com/ansible/ansible/blob/v2.11.0/lib/ansible/module_utils/basic.py#L2091

Unfortunately, this is not thread-safe when Ansible hits Python 2 targets (eg. CentOS 7). The Python 2 standard library implements `.get()` non-atomically:
```python
    def get(self, key, failobj=None):
        if key not in self:
            return failobj
        return self[key]
```

This surfaces in Ansible primarily during the fact collection process in `module_utils/facts/hardware/linux.py`, where several threads in a `multiprocessing.pool.ThreadPool` call `run_process()` to collect block device information. When the race condition is hit, a `KeyError` is raised, breaking the mount point fact gathering and leaving the facts unavailable.

In our environment, when running against 1000+ CentOS 7 hosts, this race condition will be intermittently hit on only 1-2 hosts, making this difficult to troubleshoot. Because it's very hard to reproduce with fewer hosts, I created a script to demonstrate how the `os.environ` mutation is problematic: https://gist.github.com/agunnerson-ibm/b7a956d05095c5fad885295e2e31c9a4

Is it possible to refactor `run_command()` so that it makes a copy of `os.environ`, mutates the copy, and then passes it to `subprocess.Popen` via the `env=` kwarg? I believe that would fix this race condition and would remove the current implementation's need to back up and restore environment variables.

### Issue Type

Bug Report

### Component Name

module_utils/basic

### Ansible Version

```console
ansible [core 2.11.0]
  config file = None
  configured module search path = ['/home/jenkins/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.8/site-packages/ansible
  ansible collection location = /home/jenkins/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.8.2 (default, Feb 29 2020, 17:03:31) [GCC 9.2.0]
  jinja version = 2.11.1
  libyaml = False
```


### Configuration

```console
(none)
```


### OS / Environment

Controller:
* Alpine 3.11.2
* Python 3.8

Target hosts:
* CentOS 7.9
* Python 2.7

### Steps to Reproduce

* Run an empty playbook (in debug mode) that only gathers facts against a very large number of hosts.
* Intermittently, on a small number of hosts, mount point fact gathering will fail due to `KeyError: 'LC_ALL'`

### Expected Results

Fact gathering should not fail due to multi-threaded `os.environ` mutation

### Actual Results

Mount point fact gathering fails and mount point facts are not available


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct
the same directory can also be found
        :kw cwd: If given, working directory to run the command inside
        :kw use_unsafe_shell: See `args` parameter.  Default False
        :kw prompt_regex: Regex string (not a compiled regex) which can be
            used to detect prompts in the stdout which would otherwise cause
            the execution to hang (especially if no input data is specified)
        :kw environ_update: dictionary to *update* os.environ with
        :kw umask: Umask to be used when running the command. Default None
        :kw encoding: Since we return native strings, on python3 we need to
            know the encoding to use to transform from bytes to text.  If you
            want to always get bytes back, use encoding=None.  The default is
            "utf-8".  This does not affect transformation of strings given as
            args.
        :kw errors: Since we return native strings, on python3 we need to
            transform stdout and stderr from bytes to text.  If the bytes are
            undecodable in the ``encoding`` specified, then use this error
            handler to deal with them.  The default is ``surrogate_or_strict``
            which means that the bytes will be decoded using the
            surrogateescape error handler if available (available on all
            python3 versions we support) otherwise a UnicodeError traceback
            will be raised.  This does not affect transformations of strings
            given as args.
        :kw expand_user_and_vars: When ``use_unsafe_shell=False`` this argument
            dictates whether ``~`` is expanded in paths and environment variables
            are expanded before running the command. When ``True`` a string such as
            ``$SHELL`` will be expanded regardless of escaping. When ``False`` and
            ``use_unsafe_shell=False`` no path or variable expansion will be done.
        :kw pass_fds: When running on Python 3 this argument
            dictates which file descriptors should be passed
            to an underlying ``Popen`` constructor. On Python 2, this will