Python 3.X:为何numexpr.evaluate()性能不如eval()?
Great question! Let's break down why you're seeing numexpr underperform compared to eval() here, even though it's built to speed up numerical computations:
1. Small Dataset Size is the Biggest Culprit
numexpr's strengths shine when working with large arrays (think hundreds of thousands to millions of elements). It incurs unavoidable overhead from:
- Compiling your expression into optimized machine code
- Spawning and managing threads for parallel execution
With only 1000 elements in your x array, this overhead completely cancels out any performance gains from numexpr's optimizations. In contrast, eval() directly calls numpy's highly tuned vectorized operations—these are already blazingly fast for small datasets, with almost no startup cost.
2. Complex Number Overhead
Your expression involves complex arithmetic, which numexpr supports, but numpy has decades of optimized low-level implementations for complex operations. For small datasets, numpy's native vectorized complex calculations will often outpace numexpr's generalized approach, which adds a layer of abstraction that isn't worth it for tiny workloads.
3. Threading Overhead (Even When Disabled)
Even if you uncomment ne.set_num_threads(8), using multiple threads for a tiny array introduces unnecessary overhead. Thread management, data partitioning, and inter-thread communication all take time that's not justified when the computation itself is trivial.
Let's Test with a Larger Dataset
If you scale up x to, say, 1,000,000 elements, you'll likely see numexpr pull ahead. Here's a modified snippet to try:
import datetime import numpy as np import numexpr as ne expr = '11808000.0*1j*x**2*exp(2.5e-10*1j*x) + 1512000.0*1j*x**2*exp(5.0e-10*1j*x)' # Larger dataset x_large = np.array([m+3j for m in range(1, 1_000_001)]) # eval test start_eval = datetime.datetime.now() namespace = dict(x=x_large, exp=np.exp) result_eval = eval(expr, namespace) end_eval = datetime.datetime.now() print("time by using eval : %s" % (end_eval- start_eval)) # numexpr test with optimal threads ne.set_num_threads(ne.detect_number_of_cores()) start_ne = datetime.datetime.now() result_ne = ne.evaluate(expr, local_dict={'x': x_large}) end_ne = datetime.datetime.now() print("time by using numexpr: %s" % (end_ne- start_ne))
Additional Tips
- Always use
ne.detect_number_of_cores()to set thread count dynamically instead of hardcoding—it matches your CPU's actual capabilities. - For very small arrays, stick with numpy's native operations—numexpr isn't designed for this use case.
- If you're working with complex expressions regularly, consider pre-compiling them with
ne.compile()to reduce startup overhead for repeated runs.
Your original test code for reference:
import datetime import numpy as np import numexpr as ne expr = '11808000.0*1j*x**2*exp(2.5e-10*1j*x) + 1512000.0*1j*x**2*exp(5.0e-10*1j*x)' # use eval start_eval = datetime.datetime.now() namespace = dict(x=np.array([m+3j for m in range(1, 1001)]), exp=np.exp) result_eval = eval(expr, namespace) end_eval = datetime.datetime.now() # print(result) print("time by using eval : %s" % (end_eval- start_eval)) # use numexpr # ne.set_num_threads(8) start_ne = datetime.datetime.now() x = np.array([n+3j for n in range(1, 1001)]) result_ne = ne.evaluate(expr) end_ne = datetime.datetime.now() # print(result_ne) print("time by using numexpr: %s" % (end_ne- start_ne))
Original run results:
time by using eval : 0:00:00.002998
time by using numexpr: 0:00:00.052969
内容的提问来源于stack exchange,提问作者sun0727

