How to Ping Multiple Hosts in Parallel with Python ThreadPoolExecutor

A parallel host-pinging script using ThreadPoolExecutor and subprocess to check connectivity across multiple addresses concurrently.

Medium Python 3.9+ Aug 9, 2026 Automation & scripting 13 views 0 copies

Python code

34 lines
Python 3.9+
import subprocess
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path

HOSTS = [
    "google.com",
    "github.com",
    "stackoverflow.com",
    "nonexistent.invalid",
    "localhost",
]

def ping_host(host: str) -> str:
    """Ping a single host and return a status string."""
    result = subprocess.run(
        ["ping", "-c", "1", "-W", "1", host],
        capture_output=True,
        text=True,
        timeout=3,
    )
    if result.returncode == 0:
        return f"{host}: OK"
    return f"{host}: FAIL"

def ping_all(hosts: list[str], max_workers: int = 3) -> list[str]:
    """Ping all hosts in parallel using a thread pool."""
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        results = list(executor.map(ping_host, hosts))
    return results

if __name__ == "__main__":
    output = ping_all(HOSTS)
    for line in output:
        print(line)

Output

stdout
google.com: OK
github.com: OK
stackoverflow.com: OK
nonexistent.invalid: FAIL
localhost: OK

How it works

The ThreadPoolExecutor creates a pool of worker threads that call ping_host concurrently, so multiple ping subprocesses run in parallel instead of sequentially. Each subprocess.run call captures stdout/stderr, so the script is quiet unless you print results. The -c 1 and -W 1 flags limit each ping to one packet and a one-second timeout, keeping the total runtime short. Using a with block ensures all worker threads and resources are cleaned up automatically. The list(executor.map(...)) preserves the input order, making results easy to pair with hostnames.

Common mistakes

  • Forgetting to set a subprocess timeout, so a slow host blocks the thread forever
  • Using shell=True without need, increasing security risks with host input
  • Passing a generator directly to executor.map and losing the ordered results
  • Assuming ping options work identically on Windows (use -n instead of -c)

Variations

  1. Use `subprocess.run` with `check=False` and handle return codes explicitly for custom error messages
  2. Switch to `asyncio.to_thread` or `asyncio.create_subprocess_exec` for async-friendly host checks

Real-world use cases

  • Monitoring site health from a dashboard by periodically pinging key endpoints across regions.
  • Pre-deployment connectivity checks that verify all services and infrastructure are reachable.
  • Network troubleshooting scripts that quickly identify which hosts are down during an incident.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Automation & scripting

Related tutorials and quizzes for this topic.