import time
import functools
def measure_execution_time(func):
@functools.wraps(func)
def wrapper(*args, _is_recursive_call=False, **kwargs):
if not _is_recursive_call:
wrapper._start_time = time.time() # Set the start time only for the top-level call
result = func(*args, **kwargs) # Call the function
if not _is_recursive_call: # If this is the top-level call
wrapper._end_time = time.time() # Set the end time
print(f"{func.__name__} executed in {wrapper._end_time - wrapper._start_time:.3f} s.")
return result
return wrapper
@functools.cache
@measure_execution_time
def fibonacci_1(n): # Fibonacci sequence (O(2^n))
if n < 2:
return n
return fibonacci_1(n-1, _is_recursive_call=True) + fibonacci_1(n-2, _is_recursive_call=True)
@measure_execution_time
def fibonacci_2(n): # Fibonacci sequence (O(2^n))
if n < 2:
return n
return fibonacci_2(n-1, _is_recursive_call=True) + fibonacci_2(n-2, _is_recursive_call=True)
fibonacci_1(20) # Output: 0.000 s
fibonacci_1(35) # Output: 0.000 s
fibonacci_2(20) # Output: 0.004 s
fibonacci_2(35) # Output: 5.472 s
範例 – 昂貴操作
expcious_operation() 的結果將根據參數 a 和 b 進行 cache。 如果你使用相同的參數再次調用 expcious_operation(),Python 不會重新計算該函數,而是直接返回 cache 結果。
import functools
@functools.cache
def expensive_operation(a, b):
print('[Simulating an expensive operation O(a*b)]')
for i in range(a):
for j in range(b):
x = i
y = j
return a*b
print(expensive_operation(10000, 10000)) # Output: 1000000
print(expensive_operation(10000, 10000)) # Output: 1000000
範例 – 遞迴 vs 迴圈
PYTHON
import time
import functools
def measure_execution_time(func):
@functools.wraps(func)
def wrapper(*args, _is_recursive_call=False, **kwargs):
if not _is_recursive_call:
wrapper._start_time = time.time() # Set the start time only for the top-level call
result = func(*args, **kwargs) # Call the function
if not _is_recursive_call: # If this is the top-level call
wrapper._end_time = time.time() # Set the end time
print(f"{func.__name__} executed in {wrapper._end_time - wrapper._start_time:.3f} s.")
return result
return wrapper
@functools.cache
@measure_execution_time
def fibonacci_recursion(n): # Fibonacci sequence O(2^n)
if n < 2:
return n
return fibonacci_recursion(n-1, _is_recursive_call=True) + fibonacci_recursion(n-2, _is_recursive_call=True)
@functools.cache
@measure_execution_time
def fibonacci_for(n): # Fibonacci sequence O(n)
a, b = 0, 1 # Initialize
for _ in range(n):
a, b = b, a + b
return a
@functools.cache
@measure_execution_time
def fibonacci_while(n): # Fibonacci sequence O(n)
a, b = 0, 1 # Initialize
while n > 0:
a, b = b, a + b
n -= 1
return a
fibonacci_recursion(20) # Output: 0.000 s
fibonacci_recursion(35) # Output: 0.000 s
fibonacci_for(20) # Output: 0.000 s
fibonacci_for(35) # Output: 0.000 s
fibonacci_while(20) # Output: 0.000 s
fibonacci_while(35) # Output: 0.000 s
import functools
@functools.lru_cache(maxsize=128, typed=True)
def add(x, y):
return x + y
add(3, 4) # Will be cached
print(add.cache_info())
add(3.0, 4.0) # Will be cached (typed=True)
print(add.cache_info())
add(x=3.0, y=4.0) # Will be cached (argument patterns)
print(add.cache_info())
add(y=4.0, x=3.0) # Will be cached (argument patterns)
print(add.cache_info())
add(x=3.0, y=4.0)
print(add.cache_info())
add.cache_clear() # Clear the cache
print(add.cache_info())
import functools
import threading
from concurrent.futures import ThreadPoolExecutor
# Define a lock
lock = threading.Lock()
# Time-consuming operation
def expensive_operation(n):
return n * n
# Thread safety measures
@functools.lru_cache
def thread_safe_expensive_operation(n):
with lock:
return expensive_operation(n)
# Using ThreadPoolExecutor
with ThreadPoolExecutor() as executor:
# Submit tasks
futures = [executor.submit(thread_safe_expensive_operation, i) for i in range(35)]
# Print results
for future in futures:
print(future.result())
PYTHON
import functools
import threading
from concurrent.futures import ThreadPoolExecutor
# Define a lock
lock = threading.Lock()
# Fibonacci sequence
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# Thread safety measures
@functools.lru_cache
def thread_safe_expensive_operation(n):
with lock:
return fibonacci(n)
# Using ThreadPoolExecutor
with ThreadPoolExecutor() as executor:
# Submit tasks
futures = [executor.submit(thread_safe_expensive_operation, i) for i in range(35)]
# Print results
for future in futures:
print(future.result())
Non-thread safe:
PYTHON
import functools
from concurrent.futures import ThreadPoolExecutor
# Time-consuming operation
@functools.lru_cache
def fibonacci_recursion(n): # Fibonacci sequence
if n < 2:
return n
return fibonacci_recursion(n-1) + fibonacci_recursion(n-2)
# Using ThreadPoolExecutor
with ThreadPoolExecutor() as executor:
# Submit tasks
futures = [executor.submit(fibonacci_recursion, i) for i in range(35)]
# Print results
for future in futures:
print(future.result())
import time
import threading
import concurrent.futures
from functools import cached_property
class ExpensiveObject:
def __init__(self):
self._expensive_data = None
@cached_property
def expensive_data(self):
print("Performing complex operation...")
time.sleep(2)
return sum(i * i for i in range(10000)) # 假設是複雜的 operation
def worker(obj):
print(f"Thread {threading.current_thread().name}: {obj.expensive_data}")
if __name__ == "__main__":
obj = ExpensiveObject()
with concurrent.futures.ThreadPoolExecutor(thread_name_prefix="WorkerThread", max_workers=3) as executor:
for _ in range(5):
executor.submit(worker, obj)