Python time.process_time_ns Function
Last modified April 11, 2025
This comprehensive guide explores Python's time.process_time_ns
function,
which returns process time in nanoseconds. We'll cover high-precision timing,
performance measurement, and practical examples.
Basic Definitions
The time.process_time_ns
function returns the current process time
as an integer in nanoseconds. Process time measures CPU time used by the process.
Key characteristics: nanosecond precision, measures CPU time (not wall-clock), and excludes sleep time. It's ideal for benchmarking CPU-bound operations. The return value is an integer for precise timing measurements.
Basic Process Time Measurement
The simplest use of time.process_time_ns
measures process time.
This example shows basic usage and conversion to seconds.
import time # Get current process time in nanoseconds process_time_ns = time.process_time_ns() print(f"Process time: {process_time_ns} ns") # Convert to seconds process_time_sec = process_time_ns / 1e9 print(f"Process time: {process_time_sec:.9f} seconds")
This example demonstrates getting the current process time in nanoseconds. The value is converted to seconds for human-readable display.
Note that process time only increases while the CPU is actively working on your process, unlike wall-clock time.
Measuring Function Execution Time
time.process_time_ns
is ideal for measuring CPU time of functions.
This example shows how to time a CPU-intensive operation.
import time def calculate_primes(n): primes = [] for candidate in range(2, n + 1): is_prime = True for divisor in range(2, int(candidate ** 0.5) + 1): if candidate % divisor == 0: is_prime = False break if is_prime: primes.append(candidate) return primes # Start timer start_time = time.process_time_ns() # Execute CPU-bound function primes = calculate_primes(10000) # Calculate duration end_time = time.process_time_ns() duration_ns = end_time - start_time print(f"Found {len(primes)} primes in {duration_ns / 1e6:.3f} ms")
This pattern measures only the CPU time used by the calculation, excluding any time spent waiting or sleeping. The result is in nanoseconds.
The duration is converted to milliseconds for better readability while maintaining precision.
Comparing Process Time and Wall Time
This example compares process time with wall-clock time to show the difference when including sleep operations.
import time def mixed_operation(): # CPU-bound work sum(range(1000000)) # I/O-bound wait time.sleep(1) # More CPU work sum(range(2000000)) # Wall-clock time measurement wall_start = time.time() mixed_operation() wall_end = time.time() print(f"Wall time: {(wall_end - wall_start) * 1e3:.3f} ms") # Process time measurement proc_start = time.process_time_ns() mixed_operation() proc_end = time.process_time_ns() print(f"Process time: {(proc_end - proc_start) / 1e6:.3f} ms")
Wall time includes sleep time, while process time only counts active CPU usage. This shows how they differ for operations with waiting periods.
Process time is better for measuring actual CPU workload, while wall time measures total elapsed time.
Microbenchmarking with process_time_ns
For microbenchmarks, process_time_ns
provides nanosecond precision.
This example benchmarks a small operation multiple times.
import time def benchmark(func, iterations=1000000): start = time.process_time_ns() for _ in range(iterations): func() end = time.process_time_ns() ns_per_op = (end - start) / iterations print(f"{func.__name__}: {ns_per_op:.2f} ns/operation") def empty_func(): pass def small_calc(): 3.14159 * 2.71828 benchmark(empty_func) benchmark(small_calc)
This measures the per-operation cost by running many iterations and dividing the total time. Nanosecond precision reveals small performance differences.
Note that modern CPUs may optimize empty loops, so results should be interpreted carefully.
Profiling Code Sections
process_time_ns
can profile different code sections separately.
This example shows detailed CPU time breakdown.
import time def complex_operation(): # Section 1: Setup start1 = time.process_time_ns() data = [i**2 for i in range(10000)] end1 = time.process_time_ns() # Section 2: Processing start2 = time.process_time_ns() result = sum(x % 7 for x in data) end2 = time.process_time_ns() # Section 3: Cleanup start3 = time.process_time_ns() sorted_data = sorted(data) end3 = time.process_time_ns() # Report timings print(f"Setup: {(end1 - start1) / 1e6:.3f} ms") print(f"Processing: {(end2 - start2) / 1e6:.3f} ms") print(f"Cleanup: {(end3 - start3) / 1e6:.3f} ms") return result complex_operation()
This pattern helps identify which parts of a function consume the most CPU time. Each section is timed independently for detailed analysis.
The results are converted to milliseconds for readability while maintaining precise measurement of each section.
Comparing Algorithms
This example uses process_time_ns
to compare the performance of
different algorithms solving the same problem.
import time def factorial_recursive(n): return 1 if n <= 1 else n * factorial_recursive(n - 1) def factorial_iterative(n): result = 1 for i in range(1, n + 1): result *= i return result def time_algorithm(func, arg): start = time.process_time_ns() result = func(arg) end = time.process_time_ns() return result, end - start n = 500 result_rec, time_rec = time_algorithm(factorial_recursive, n) result_it, time_it = time_algorithm(factorial_iterative, n) print(f"Recursive: {time_rec / 1e6:.3f} ms") print(f"Iterative: {time_it / 1e6:.3f} ms") print(f"Same result: {result_rec == result_it}")
The example compares recursive and iterative factorial implementations. Process time measurement shows which approach is more CPU-efficient.
Note that for very large n, the recursive version might hit Python's recursion limit before showing its full performance characteristics.
Tracking Cumulative Process Time
This example demonstrates tracking cumulative CPU time across multiple operations
using process_time_ns
.
import time import random def perform_work(): # Simulate variable CPU workload n = random.randint(100000, 500000) sum(range(n)) total_cpu_ns = 0 operations = 0 while total_cpu_ns < 5e9: # Run until 5 seconds CPU time start = time.process_time_ns() perform_work() end = time.process_time_ns() operation_time = end - start total_cpu_ns += operation_time operations += 1 print(f"Op {operations}: {operation_time / 1e6:.3f} ms", end=" | ") print(f"Total: {total_cpu_ns / 1e9:.3f} s") print(f"\nCompleted {operations} operations in {total_cpu_ns / 1e9:.3f} s CPU time")
This tracks the total CPU time consumed by a series of operations until reaching a threshold. Each operation's contribution is measured precisely.
The example shows how to monitor cumulative CPU usage for batch processing or long-running tasks.
Best Practices
- Precision needs: Use process_time_ns for nanosecond precision CPU timing
- CPU-bound work: Ideal for measuring actual CPU usage, not I/O time
- Microbenchmarks: Perfect for small, fast operations needing high precision
- Comparisons: Use for relative performance measurements between algorithms
- Multi-threading: Be aware that process time includes all threads
Source References
Author
List all Python tutorials.