Introduction
Performance optimization requires understanding where time is spent and making targeted improvements. This guide covers profiling techniques, common bottlenecks, and optimization strategies.
First, measure. Then optimize.
Profiling
Python Profiling
import cProfile
import pstats
from io import StringIO
def profile_function(func, *args, **kwargs):
"""Profile a function."""
profiler = cProfile.Profile()
profiler.enable()
result = func(*args, **kwargs)
profiler.disable()
# Print stats
s = StringIO()
ps = pstats.Stats(profiler, stream=s).sort_stats('cumulative')
ps.print_stats(20)
print(s.getvalue())
return result
# Using line_profiler
# pip install line_profiler
# @profile decorator
from line_profiler import LineProfiler
def slow_function():
result = 0
for i in range(10000):
result += i ** 2
return result
# Run with: kernprof -l -v script.py
JavaScript Profiling
// Chrome DevTools Profiling
// 1. Open DevTools
// 2. Performance tab
// 3. Click Record
// 4. Perform actions
// 5. Stop and analyze
// Programmatic profiling
console.time('myOperation');
// Do operation
console.timeEnd('myOperation');
// Performance Mark
performance.mark('operation-start');
// Do operation
performance.mark('operation-end');
performance.measure('operation', 'operation-start', 'operation-end');
Common Bottlenecks
Database Queries
# โ N+1 Query Problem
def get_users_with_posts():
users = db.query(User).all()
for user in users:
# This runs N queries!
posts = db.query(Post).filter_by(user_id=user.id).all()
user.posts = posts
return users
# โ
Optimized
def get_users_with_posts():
# Eager loading
users = db.query(User).options(
joinedload(User.posts)
).all()
return users
Caching
# โ Repeated expensive computation
def calculate_total(order_id):
order = get_order(order_id)
total = 0
for item in order.items:
# Recalculates tax every time!
tax = calculate_tax(item.price)
total += item.price + tax
return total
# โ
Cached
from functools import lru_cache
@lru_cache(maxsize=1000)
def get_tax_rate(state):
# Expensive lookup - now cached
return database.query_tax_rate(state)
Benchmarking
import timeit
def slow_way():
result = []
for i in range(1000):
if i % 2 == 0:
result.append(i)
return result
def fast_way():
return [i for i in range(1000) if i % 2 == 0]
# Benchmark
slow_time = timeit.timeit(slow_way, number=10000)
fast_time = timeit.timeit(fast_way, number=10000)
print(f"Slow: {slow_time:.3f}s")
print(f"Fast: {fast_time:.3f}s")
print(f"Speedup: {slow_time/fast_time:.1f}x")
Optimization Techniques
Algorithm Optimization
# โ O(nยฒ) - Nested loops
def find_duplicates_slow(items):
duplicates = []
for i in range(len(items)):
for j in range(i + 1, len(items)):
if items[i] == items[j]:
duplicates.append(items[i])
return duplicates
# โ
O(n) - Using set
def find_duplicates_fast(items):
seen = set()
duplicates = []
for item in items:
if item in seen:
duplicates.append(item)
seen.add(item)
return duplicates
Lazy Evaluation
# โ Eager loading - load everything
def get_top_users():
all_users = db.query(User).all() # Load all!
return sorted(all_users, key=lambda u: u.score)[:10]
# โ
Lazy - only load what we need
def get_top_users():
return db.query(User).order_by(
User.score.desc()
).limit(10).all()
Database Optimization
Indexing
-- Create index for frequently queried column
CREATE INDEX idx_users_email ON users(email);
-- Composite index for multi-column queries
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at DESC);
-- Partial index for specific queries
CREATE INDEX idx_active_orders ON orders(user_id)
WHERE status = 'active';
-- Analyze query plan
EXPLAIN ANALYZE SELECT * FROM users WHERE email = '[email protected]';
Best Practices
- Measure first: Don’t optimize without data
- Profile in production-like environment: Staging isn’t enough
- Optimize the biggest bottleneck: Small gains elsewhere don’t matter
- Verify improvements: Measure after changes
- Document trade-offs: Optimizations often have costs
Conclusion
Performance optimization is about finding and fixing the actual bottlenecks. Use profiling tools to identify where time is spent, then make targeted improvements. Always measure before and after.
Resources
- Python Profiling Documentation - Official profiling guide
- Chrome DevTools Performance - Browser profiling
- PySpy - Sampling profiler for Python
- web.dev Performance - Web performance guide
Comments