Python
Threading
Thread ID
Programming
Python Tips

How to obtain a Thread id in Python?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Every thread in Python has a unique identifier that distinguishes it from other threads. You need this identifier for logging, debugging, and correlating work across concurrent operations. Python provides several ways to get a thread's ID depending on whether you need the Python-level identifier or the operating system's native thread ID. The two main approaches are threading.get_ident() for the Python thread ID and threading.get_native_id() (Python 3.8+) for the OS-level thread ID.

Python Thread ID with threading.get_ident()

python
1import threading
2
3def worker():
4    thread_id = threading.get_ident()
5    print(f"Worker thread ID: {thread_id}")
6
7t = threading.Thread(target=worker)
8t.start()
9t.join()
10
11# From the main thread
12print(f"Main thread ID: {threading.get_ident()}")

threading.get_ident() returns an integer that uniquely identifies the current thread among all active threads. This value is recycled when a thread exits and a new one is created, so it is only unique while the thread is alive.

OS-Level Thread ID with threading.get_native_id()

python
1import threading
2
3def worker():
4    native_id = threading.get_native_id()
5    print(f"OS thread ID: {native_id}")
6
7t = threading.Thread(target=worker)
8t.start()
9t.join()
10
11print(f"Main OS thread ID: {threading.get_native_id()}")

threading.get_native_id() was introduced in Python 3.8. It returns the kernel-assigned thread ID (e.g., the value from gettid() on Linux or GetCurrentThreadId() on Windows). This ID is useful when correlating Python threads with OS-level monitoring tools like htop, top, or strace.

Thread Object Attributes

python
1import threading
2
3def worker():
4    current = threading.current_thread()
5    print(f"Name: {current.name}")
6    print(f"Ident: {current.ident}")
7    print(f"Native ID: {current.native_id}")
8
9t = threading.Thread(target=worker, name="MyWorker")
10t.start()
11t.join()
12
13# Access from outside the thread
14print(f"Thread ident after start: {t.ident}")
15print(f"Thread native_id after start: {t.native_id}")

The threading.Thread object exposes .ident and .native_id (Python 3.8+) as attributes. These are None before the thread starts and get populated once it begins running.

Logging with Thread IDs

python
1import logging
2import threading
3
4logging.basicConfig(
5    format="%(asctime)s [%(threadName)s %(thread)d] %(message)s",
6    level=logging.INFO,
7)
8
9def worker():
10    logging.info("Processing task")
11
12threads = [threading.Thread(target=worker, name=f"Worker-{i}") for i in range(3)]
13for t in threads:
14    t.start()
15for t in threads:
16    t.join()

The logging module supports %(thread)d for the Python thread ID and %(threadName)s for the thread name. This makes it straightforward to trace which thread produced each log line without calling get_ident() manually.

Enumerating All Active Threads

python
1import threading
2import time
3
4def long_task():
5    time.sleep(2)
6
7threads = [threading.Thread(target=long_task, name=f"Task-{i}") for i in range(3)]
8for t in threads:
9    t.start()
10
11# List all active threads
12for t in threading.enumerate():
13    print(f"Thread: {t.name}, ID: {t.ident}, Alive: {t.is_alive()}")

threading.enumerate() returns a list of all active Thread objects. Each object has .ident, .name, and .native_id attributes that you can inspect for monitoring or debugging.

Mapping Thread IDs to concurrent.futures

python
1from concurrent.futures import ThreadPoolExecutor
2import threading
3
4def task(n):
5    tid = threading.get_ident()
6    return f"Task {n} ran on thread {tid}"
7
8with ThreadPoolExecutor(max_workers=3) as pool:
9    futures = [pool.submit(task, i) for i in range(6)]
10    for f in futures:
11        print(f.result())

When using ThreadPoolExecutor, the pool reuses threads. Calling threading.get_ident() inside the task function reveals which pool thread executed the task. Multiple tasks may share the same thread ID because the pool recycles threads.

Difference Between ident and native_id

Attributethreading.get_ident()threading.get_native_id()
Python versionAll versions3.8+
SourcePython runtimeOperating system kernel
RecycledYes, when thread exitsNo, unique per OS thread lifetime
Use caseIn-process identificationOS-level debugging (htop, strace)
PlatformAllLinux, macOS, Windows, FreeBSD

Common Pitfalls

  • Checking ident before start(): thread.ident is None until the thread actually starts running. Always call t.start() before reading t.ident.
  • Assuming ident is globally unique: Python recycles thread IDs after a thread exits. Two threads that never overlap in time can share the same ident. Use native_id if you need OS-level uniqueness.
  • Using get_native_id() on Python < 3.8: threading.get_native_id() raises AttributeError on older Python versions. Check sys.version_info >= (3, 8) or use threading.get_ident() as a fallback.
  • Confusing thread ID with process ID: threading.get_ident() identifies a thread within a process. For the process ID, use os.getpid(). In multiprocessing code, you need both to uniquely identify a worker.
  • GIL and true parallelism: Thread IDs prove threads exist, but the GIL prevents CPU-bound Python threads from running simultaneously. For CPU-bound parallelism, use multiprocessing and os.getpid() instead.

Summary

  • Use threading.get_ident() for the Python-level thread ID (available in all Python versions)
  • Use threading.get_native_id() for the OS kernel thread ID (Python 3.8+)
  • Access .ident and .native_id on Thread objects after calling .start()
  • Use %(thread)d in logging format strings to automatically include thread IDs
  • threading.enumerate() lists all active threads with their identifiers
  • Thread IDs from get_ident() are recycled — do not use them as permanent unique keys

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.