We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
faster check for docker running
currently this is how pre-commit checks if docker is available:

https://github.com/pre-commit/pre-commit/blob/9a5461db24beeee9960423b853cfbfbaefb6cc7a/pre_commit/languages/docker.py#L29-L41

there's two low-hanging-fruit problems with this:

1. it is checked repeatedly, but can probably be checked just once per process (can use [`functools.lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache) as a "run once" decorator)
2. `docker ps` is pretty slow, there's probably a faster way to see if docker is available -- on my machine it takes _more than a second_! even without containers
   ```console
   $ time docker ps
   CONTAINER ID  IMAGE   COMMAND  CREATED  STATUS  PORTS   NAMES

   real	0m1.169s
   user	0m0.088s
   sys	0m0.085s
   ```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pre_commit/languages/docker.py`
Content:
```
1 import hashlib
2 import os
3 from typing import Sequence
4 from typing import Tuple
5 
6 import pre_commit.constants as C
7 from pre_commit.hook import Hook
8 from pre_commit.languages import helpers
9 from pre_commit.prefix import Prefix
10 from pre_commit.util import CalledProcessError
11 from pre_commit.util import clean_path_on_failure
12 from pre_commit.util import cmd_output_b
13 
14 ENVIRONMENT_DIR = 'docker'
15 PRE_COMMIT_LABEL = 'PRE_COMMIT'
16 get_default_version = helpers.basic_get_default_version
17 healthy = helpers.basic_healthy
18 
19 
20 def md5(s: str) -> str:  # pragma: win32 no cover
21     return hashlib.md5(s.encode()).hexdigest()
22 
23 
24 def docker_tag(prefix: Prefix) -> str:  # pragma: win32 no cover
25     md5sum = md5(os.path.basename(prefix.prefix_dir)).lower()
26     return f'pre-commit-{md5sum}'
27 
28 
29 def docker_is_running() -> bool:  # pragma: win32 no cover
30     try:
31         cmd_output_b('docker', 'ps')
32     except CalledProcessError:
33         return False
34     else:
35         return True
36 
37 
38 def assert_docker_available() -> None:  # pragma: win32 no cover
39     assert docker_is_running(), (
40         'Docker is either not running or not configured in this environment'
41     )
42 
43 
44 def build_docker_image(
45         prefix: Prefix,
46         *,
47         pull: bool,
48 ) -> None:  # pragma: win32 no cover
49     cmd: Tuple[str, ...] = (
50         'docker', 'build',
51         '--tag', docker_tag(prefix),
52         '--label', PRE_COMMIT_LABEL,
53     )
54     if pull:
55         cmd += ('--pull',)
56     # This must come last for old versions of docker.  See #477
57     cmd += ('.',)
58     helpers.run_setup_cmd(prefix, cmd)
59 
60 
61 def install_environment(
62         prefix: Prefix, version: str, additional_dependencies: Sequence[str],
63 ) -> None:  # pragma: win32 no cover
64     helpers.assert_version_default('docker', version)
65     helpers.assert_no_additional_deps('docker', additional_dependencies)
66     assert_docker_available()
67 
68     directory = prefix.path(
69         helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),
70     )
71 
72     # Docker doesn't really have relevant disk environment, but pre-commit
73     # still needs to cleanup its state files on failure
74     with clean_path_on_failure(directory):
75         build_docker_image(prefix, pull=True)
76         os.mkdir(directory)
77 
78 
79 def get_docker_user() -> Tuple[str, ...]:  # pragma: win32 no cover
80     try:
81         return ('-u', f'{os.getuid()}:{os.getgid()}')
82     except AttributeError:
83         return ()
84 
85 
86 def docker_cmd() -> Tuple[str, ...]:  # pragma: win32 no cover
87     return (
88         'docker', 'run',
89         '--rm',
90         *get_docker_user(),
91         # https://docs.docker.com/engine/reference/commandline/run/#mount-volumes-from-container-volumes-from
92         # The `Z` option tells Docker to label the content with a private
93         # unshared label. Only the current container can use a private volume.
94         '-v', f'{os.getcwd()}:/src:rw,Z',
95         '--workdir', '/src',
96     )
97 
98 
99 def run_hook(
100         hook: Hook,
101         file_args: Sequence[str],
102         color: bool,
103 ) -> Tuple[int, bytes]:  # pragma: win32 no cover
104     assert_docker_available()
105     # Rebuild the docker image in case it has gone missing, as many people do
106     # automated cleanup of docker images.
107     build_docker_image(hook.prefix, pull=False)
108 
109     hook_cmd = hook.cmd
110     entry_exe, cmd_rest = hook.cmd[0], hook_cmd[1:]
111 
112     entry_tag = ('--entrypoint', entry_exe, docker_tag(hook.prefix))
113     cmd = docker_cmd() + entry_tag + cmd_rest
114     return helpers.run_xargs(hook, cmd, file_args, color=color)
115
```

Path: `pre_commit/languages/docker_image.py`
Content:
```
1 from typing import Sequence
2 from typing import Tuple
3 
4 from pre_commit.hook import Hook
5 from pre_commit.languages import helpers
6 from pre_commit.languages.docker import assert_docker_available
7 from pre_commit.languages.docker import docker_cmd
8 
9 ENVIRONMENT_DIR = None
10 get_default_version = helpers.basic_get_default_version
11 healthy = helpers.basic_healthy
12 install_environment = helpers.no_install
13 
14 
15 def run_hook(
16         hook: Hook,
17         file_args: Sequence[str],
18         color: bool,
19 ) -> Tuple[int, bytes]:  # pragma: win32 no cover
20     assert_docker_available()
21     cmd = docker_cmd() + hook.cmd
22     return helpers.run_xargs(hook, cmd, file_args, color=color)
23
```
--- 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/pre_commit/languages/docker.py b/pre_commit/languages/docker.py
--- a/pre_commit/languages/docker.py
+++ b/pre_commit/languages/docker.py
@@ -7,9 +7,7 @@
 from pre_commit.hook import Hook
 from pre_commit.languages import helpers
 from pre_commit.prefix import Prefix
-from pre_commit.util import CalledProcessError
 from pre_commit.util import clean_path_on_failure
-from pre_commit.util import cmd_output_b
 
 ENVIRONMENT_DIR = 'docker'
 PRE_COMMIT_LABEL = 'PRE_COMMIT'
@@ -26,21 +24,6 @@
     return f'pre-commit-{md5sum}'
 
 
-def docker_is_running() -> bool:  # pragma: win32 no cover
-    try:
-        cmd_output_b('docker', 'ps')
-    except CalledProcessError:
-        return False
-    else:
-        return True
-
-
-def assert_docker_available() -> None:  # pragma: win32 no cover
-    assert docker_is_running(), (
-        'Docker is either not running or not configured in this environment'
-    )
-
-
 def build_docker_image(
         prefix: Prefix,
         *,
@@ -63,7 +46,6 @@
 ) -> None:  # pragma: win32 no cover
     helpers.assert_version_default('docker', version)
     helpers.assert_no_additional_deps('docker', additional_dependencies)
-    assert_docker_available()
 
     directory = prefix.path(
         helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),
@@ -101,7 +83,6 @@
         file_args: Sequence[str],
         color: bool,
 ) -> Tuple[int, bytes]:  # pragma: win32 no cover
-    assert_docker_available()
     # Rebuild the docker image in case it has gone missing, as many people do
     # automated cleanup of docker images.
     build_docker_image(hook.prefix, pull=False)
diff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py
--- a/pre_commit/languages/docker_image.py
+++ b/pre_commit/languages/docker_image.py
@@ -3,7 +3,6 @@
 
 from pre_commit.hook import Hook
 from pre_commit.languages import helpers
-from pre_commit.languages.docker import assert_docker_available
 from pre_commit.languages.docker import docker_cmd
 
 ENVIRONMENT_DIR = None
@@ -17,6 +16,5 @@
         file_args: Sequence[str],
         color: bool,
 ) -> Tuple[int, bytes]:  # pragma: win32 no cover
-    assert_docker_available()
     cmd = docker_cmd() + hook.cmd
     return helpers.run_xargs(hook, cmd, file_args, color=color)

{"golden_diff": "diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py\n--- a/pre_commit/languages/docker.py\n+++ b/pre_commit/languages/docker.py\n@@ -7,9 +7,7 @@\n from pre_commit.hook import Hook\n from pre_commit.languages import helpers\n from pre_commit.prefix import Prefix\n-from pre_commit.util import CalledProcessError\n from pre_commit.util import clean_path_on_failure\n-from pre_commit.util import cmd_output_b\n \n ENVIRONMENT_DIR = 'docker'\n PRE_COMMIT_LABEL = 'PRE_COMMIT'\n@@ -26,21 +24,6 @@\n     return f'pre-commit-{md5sum}'\n \n \n-def docker_is_running() -> bool:  # pragma: win32 no cover\n-    try:\n-        cmd_output_b('docker', 'ps')\n-    except CalledProcessError:\n-        return False\n-    else:\n-        return True\n-\n-\n-def assert_docker_available() -> None:  # pragma: win32 no cover\n-    assert docker_is_running(), (\n-        'Docker is either not running or not configured in this environment'\n-    )\n-\n-\n def build_docker_image(\n         prefix: Prefix,\n         *,\n@@ -63,7 +46,6 @@\n ) -> None:  # pragma: win32 no cover\n     helpers.assert_version_default('docker', version)\n     helpers.assert_no_additional_deps('docker', additional_dependencies)\n-    assert_docker_available()\n \n     directory = prefix.path(\n         helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),\n@@ -101,7 +83,6 @@\n         file_args: Sequence[str],\n         color: bool,\n ) -> Tuple[int, bytes]:  # pragma: win32 no cover\n-    assert_docker_available()\n     # Rebuild the docker image in case it has gone missing, as many people do\n     # automated cleanup of docker images.\n     build_docker_image(hook.prefix, pull=False)\ndiff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py\n--- a/pre_commit/languages/docker_image.py\n+++ b/pre_commit/languages/docker_image.py\n@@ -3,7 +3,6 @@\n \n from pre_commit.hook import Hook\n from pre_commit.languages import helpers\n-from pre_commit.languages.docker import assert_docker_available\n from pre_commit.languages.docker import docker_cmd\n \n ENVIRONMENT_DIR = None\n@@ -17,6 +16,5 @@\n         file_args: Sequence[str],\n         color: bool,\n ) -> Tuple[int, bytes]:  # pragma: win32 no cover\n-    assert_docker_available()\n     cmd = docker_cmd() + hook.cmd\n     return helpers.run_xargs(hook, cmd, file_args, color=color)\n", "issue": "faster check for docker running\ncurrently this is how pre-commit checks if docker is available:\r\n\r\nhttps://github.com/pre-commit/pre-commit/blob/9a5461db24beeee9960423b853cfbfbaefb6cc7a/pre_commit/languages/docker.py#L29-L41\r\n\r\nthere's two low-hanging-fruit problems with this:\r\n\r\n1. it is checked repeatedly, but can probably be checked just once per process (can use [`functools.lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache) as a \"run once\" decorator)\r\n2. `docker ps` is pretty slow, there's probably a faster way to see if docker is available -- on my machine it takes _more than a second_! even without containers\r\n   ```console\r\n   $ time docker ps\r\n   CONTAINER ID  IMAGE   COMMAND  CREATED  STATUS  PORTS   NAMES\r\n\r\n   real\t0m1.169s\r\n   user\t0m0.088s\r\n   sys\t0m0.085s\r\n   ```\n", "before_files": [{"content": "import hashlib\nimport os\nfrom typing import Sequence\nfrom typing import Tuple\n\nimport pre_commit.constants as C\nfrom pre_commit.hook import Hook\nfrom pre_commit.languages import helpers\nfrom pre_commit.prefix import Prefix\nfrom pre_commit.util import CalledProcessError\nfrom pre_commit.util import clean_path_on_failure\nfrom pre_commit.util import cmd_output_b\n\nENVIRONMENT_DIR = 'docker'\nPRE_COMMIT_LABEL = 'PRE_COMMIT'\nget_default_version = helpers.basic_get_default_version\nhealthy = helpers.basic_healthy\n\n\ndef md5(s: str) -> str:  # pragma: win32 no cover\n    return hashlib.md5(s.encode()).hexdigest()\n\n\ndef docker_tag(prefix: Prefix) -> str:  # pragma: win32 no cover\n    md5sum = md5(os.path.basename(prefix.prefix_dir)).lower()\n    return f'pre-commit-{md5sum}'\n\n\ndef docker_is_running() -> bool:  # pragma: win32 no cover\n    try:\n        cmd_output_b('docker', 'ps')\n    except CalledProcessError:\n        return False\n    else:\n        return True\n\n\ndef assert_docker_available() -> None:  # pragma: win32 no cover\n    assert docker_is_running(), (\n        'Docker is either not running or not configured in this environment'\n    )\n\n\ndef build_docker_image(\n        prefix: Prefix,\n        *,\n        pull: bool,\n) -> None:  # pragma: win32 no cover\n    cmd: Tuple[str, ...] = (\n        'docker', 'build',\n        '--tag', docker_tag(prefix),\n        '--label', PRE_COMMIT_LABEL,\n    )\n    if pull:\n        cmd += ('--pull',)\n    # This must come last for old versions of docker.  See #477\n    cmd += ('.',)\n    helpers.run_setup_cmd(prefix, cmd)\n\n\ndef install_environment(\n        prefix: Prefix, version: str, additional_dependencies: Sequence[str],\n) -> None:  # pragma: win32 no cover\n    helpers.assert_version_default('docker', version)\n    helpers.assert_no_additional_deps('docker', additional_dependencies)\n    assert_docker_available()\n\n    directory = prefix.path(\n        helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),\n    )\n\n    # Docker doesn't really have relevant disk environment, but pre-commit\n    # still needs to cleanup its state files on failure\n    with clean_path_on_failure(directory):\n        build_docker_image(prefix, pull=True)\n        os.mkdir(directory)\n\n\ndef get_docker_user() -> Tuple[str, ...]:  # pragma: win32 no cover\n    try:\n        return ('-u', f'{os.getuid()}:{os.getgid()}')\n    except AttributeError:\n        return ()\n\n\ndef docker_cmd() -> Tuple[str, ...]:  # pragma: win32 no cover\n    return (\n        'docker', 'run',\n        '--rm',\n        *get_docker_user(),\n        # https://docs.docker.com/engine/reference/commandline/run/#mount-volumes-from-container-volumes-from\n        # The `Z` option tells Docker to label the content with a private\n        # unshared label. Only the current container can use a private volume.\n        '-v', f'{os.getcwd()}:/src:rw,Z',\n        '--workdir', '/src',\n    )\n\n\ndef run_hook(\n        hook: Hook,\n        file_args: Sequence[str],\n        color: bool,\n) -> Tuple[int, bytes]:  # pragma: win32 no cover\n    assert_docker_available()\n    # Rebuild the docker image in case it has gone missing, as many people do\n    # automated cleanup of docker images.\n    build_docker_image(hook.prefix, pull=False)\n\n    hook_cmd = hook.cmd\n    entry_exe, cmd_rest = hook.cmd[0], hook_cmd[1:]\n\n    entry_tag = ('--entrypoint', entry_exe, docker_tag(hook.prefix))\n    cmd = docker_cmd() + entry_tag + cmd_rest\n    return helpers.run_xargs(hook, cmd, file_args, color=color)\n", "path": "pre_commit/languages/docker.py"}, {"content": "from typing import Sequence\nfrom typing import Tuple\n\nfrom pre_commit.hook import Hook\nfrom pre_commit.languages import helpers\nfrom pre_commit.languages.docker import assert_docker_available\nfrom pre_commit.languages.docker import docker_cmd\n\nENVIRONMENT_DIR = None\nget_default_version = helpers.basic_get_default_version\nhealthy = helpers.basic_healthy\ninstall_environment = helpers.no_install\n\n\ndef run_hook(\n        hook: Hook,\n        file_args: Sequence[str],\n        color: bool,\n) -> Tuple[int, bytes]:  # pragma: win32 no cover\n    assert_docker_available()\n    cmd = docker_cmd() + hook.cmd\n    return helpers.run_xargs(hook, cmd, file_args, color=color)\n", "path": "pre_commit/languages/docker_image.py"}], "after_files": [{"content": "import hashlib\nimport os\nfrom typing import Sequence\nfrom typing import Tuple\n\nimport pre_commit.constants as C\nfrom pre_commit.hook import Hook\nfrom pre_commit.languages import helpers\nfrom pre_commit.prefix import Prefix\nfrom pre_commit.util import clean_path_on_failure\n\nENVIRONMENT_DIR = 'docker'\nPRE_COMMIT_LABEL = 'PRE_COMMIT'\nget_default_version = helpers.basic_get_default_version\nhealthy = helpers.basic_healthy\n\n\ndef md5(s: str) -> str:  # pragma: win32 no cover\n    return hashlib.md5(s.encode()).hexdigest()\n\n\ndef docker_tag(prefix: Prefix) -> str:  # pragma: win32 no cover\n    md5sum = md5(os.path.basename(prefix.prefix_dir)).lower()\n    return f'pre-commit-{md5sum}'\n\n\ndef build_docker_image(\n        prefix: Prefix,\n        *,\n        pull: bool,\n) -> None:  # pragma: win32 no cover\n    cmd: Tuple[str, ...] = (\n        'docker', 'build',\n        '--tag', docker_tag(prefix),\n        '--label', PRE_COMMIT_LABEL,\n    )\n    if pull:\n        cmd += ('--pull',)\n    # This must come last for old versions of docker.  See #477\n    cmd += ('.',)\n    helpers.run_setup_cmd(prefix, cmd)\n\n\ndef install_environment(\n        prefix: Prefix, version: str, additional_dependencies: Sequence[str],\n) -> None:  # pragma: win32 no cover\n    helpers.assert_version_default('docker', version)\n    helpers.assert_no_additional_deps('docker', additional_dependencies)\n\n    directory = prefix.path(\n        helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),\n    )\n\n    # Docker doesn't really have relevant disk environment, but pre-commit\n    # still needs to cleanup its state files on failure\n    with clean_path_on_failure(directory):\n        build_docker_image(prefix, pull=True)\n        os.mkdir(directory)\n\n\ndef get_docker_user() -> Tuple[str, ...]:  # pragma: win32 no cover\n    try:\n        return ('-u', f'{os.getuid()}:{os.getgid()}')\n    except AttributeError:\n        return ()\n\n\ndef docker_cmd() -> Tuple[str, ...]:  # pragma: win32 no cover\n    return (\n        'docker', 'run',\n        '--rm',\n        *get_docker_user(),\n        # https://docs.docker.com/engine/reference/commandline/run/#mount-volumes-from-container-volumes-from\n        # The `Z` option tells Docker to label the content with a private\n        # unshared label. Only the current container can use a private volume.\n        '-v', f'{os.getcwd()}:/src:rw,Z',\n        '--workdir', '/src',\n    )\n\n\ndef run_hook(\n        hook: Hook,\n        file_args: Sequence[str],\n        color: bool,\n) -> Tuple[int, bytes]:  # pragma: win32 no cover\n    # Rebuild the docker image in case it has gone missing, as many people do\n    # automated cleanup of docker images.\n    build_docker_image(hook.prefix, pull=False)\n\n    hook_cmd = hook.cmd\n    entry_exe, cmd_rest = hook.cmd[0], hook_cmd[1:]\n\n    entry_tag = ('--entrypoint', entry_exe, docker_tag(hook.prefix))\n    cmd = docker_cmd() + entry_tag + cmd_rest\n    return helpers.run_xargs(hook, cmd, file_args, color=color)\n", "path": "pre_commit/languages/docker.py"}, {"content": "from typing import Sequence\nfrom typing import Tuple\n\nfrom pre_commit.hook import Hook\nfrom pre_commit.languages import helpers\nfrom pre_commit.languages.docker import docker_cmd\n\nENVIRONMENT_DIR = None\nget_default_version = helpers.basic_get_default_version\nhealthy = helpers.basic_healthy\ninstall_environment = helpers.no_install\n\n\ndef run_hook(\n        hook: Hook,\n        file_args: Sequence[str],\n        color: bool,\n) -> Tuple[int, bytes]:  # pragma: win32 no cover\n    cmd = docker_cmd() + hook.cmd\n    return helpers.run_xargs(hook, cmd, file_args, color=color)\n", "path": "pre_commit/languages/docker_image.py"}]}