> ## Documentation Index
> Fetch the complete documentation index at: https://docs.honeyhive.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-Threading (Python)

> How to trace multi-threaded applications in Python with HoneyHive.

Since many LLM operations tend to be I/O bound, it is often useful to use threads to perform multiple operations at once.
Usually, you'll use the `ThreadPoolExecutor` class from the `concurrent.futures` module in the Python standard library, like this:

```python theme={null}
indexes = [pinecone.Index(f"index{i}") for i in range(3)]
executor = ThreadPoolExecutor(max_workers=3)
for i in range(3):
    executor.submit(indexes[i].query, [1.0, 2.0, 3.0], top_k=10)
```

Unfortunately, this won't work as you expect and may cause you to see "broken" traces or missing spans.

The reason relies in how OpenTelemetry (which is what we use under the hood for tracing) uses [Python's context](https://docs.python.org/3/library/contextvars.html) to propagate the trace.

You'll need to explicitly propagate the context to the threads:

```python theme={null}
import contextvars
import functools

indexes = [pinecone.Index(f"index{i}") for i in range(3)]
executor = ThreadPoolExecutor(max_workers=3)
for i in range(3):
    # Copy context for EACH submit call
    ctx = contextvars.copy_context()
    executor.submit(
        ctx.run,
        functools.partial(indexes[i].query, [1.0, 2.0, 3.0], top_k=10),
    )
```

<Warning>
  **You must copy the context for each `executor.submit()` call.**

  A common mistake is to copy the context once and reuse it:

  ```python theme={null}
  # WRONG - causes race conditions and missing spans
  ctx = contextvars.copy_context()  # Only copied once!
  for i in range(3):
      executor.submit(ctx.run, my_function)  # All threads share same ctx
  ```

  This causes race conditions when multiple threads call `ctx.run()` simultaneously on the same context object, resulting in missing or orphaned spans.

  Always copy inside the loop:

  ```python theme={null}
  # CORRECT - each thread gets its own context copy
  for i in range(3):
      ctx = contextvars.copy_context()  # Fresh copy for each submit
      executor.submit(ctx.run, my_function)
  ```
</Warning>

### Learn more

<CardGroup>
  <Card title="Tracer Initialization" icon="gear" href="/v2/tracing/tracer-initialization">
    Configure session handling for web servers and concurrent workloads.
  </Card>

  <Card title="Multi-Instance Tracing" icon="layer-group" href="/v2/tracing/multi-instance">
    Run multiple independent tracer instances in the same process.
  </Card>

  <Card title="Distributed Tracing" icon="network-wired" href="/v2/tracing/distributed-tracing">
    Propagate traces across service boundaries.
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/v2/introduction/troubleshooting">
    Debug missing spans and broken traces.
  </Card>
</CardGroup>
