Dưới đây là một số timings mới:
import contextlib
import timeit
def work_pass():
pass
def work_fail():
1/0
def simple_catch(fn):
try:
fn()
except Exception:
pass
@contextlib.contextmanager
def catch_context():
try:
yield
except Exception:
pass
def with_catch(fn):
with catch_context():
fn()
class ManualCatchContext(object):
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
return True
def manual_with_catch(fn):
with ManualCatchContext():
fn()
preinstantiated_manual_catch_context = ManualCatchContext()
def manual_with_catch_cache(fn):
with preinstantiated_manual_catch_context:
fn()
setup = 'from __main__ import simple_catch, work_pass, work_fail, with_catch, manual_with_catch, manual_with_catch_cache'
commands = [
'simple_catch(work_pass)',
'simple_catch(work_fail)',
'with_catch(work_pass)',
'with_catch(work_fail)',
'manual_with_catch(work_pass)',
'manual_with_catch(work_fail)',
'manual_with_catch_cache(work_pass)',
'manual_with_catch_cache(work_fail)',
]
for c in commands:
print c, ': ', timeit.timeit(c, setup)
Tôi đã thực hiện simple_catch
thực sự gọi hàm và tôi đã bổ sung thêm hai tiêu chuẩn mới.
Đây là những gì tôi nhận:
>>> python2 bench.py
simple_catch(work_pass) : 0.413918972015
simple_catch(work_fail) : 3.16218209267
with_catch(work_pass) : 6.88726496696
with_catch(work_fail) : 11.8109841347
manual_with_catch(work_pass) : 1.60508012772
manual_with_catch(work_fail) : 4.03651213646
manual_with_catch_cache(work_pass) : 1.32663416862
manual_with_catch_cache(work_fail) : 3.82525682449
python2 p.py.py 33.06s user 0.00s system 99% cpu 33.099 total
Và đối với PyPy:
>>> pypy bench.py
simple_catch(work_pass) : 0.0104489326477
simple_catch(work_fail) : 0.0212869644165
with_catch(work_pass) : 0.362847089767
with_catch(work_fail) : 0.400238037109
manual_with_catch(work_pass) : 0.0223228931427
manual_with_catch(work_fail) : 0.0208241939545
manual_with_catch_cache(work_pass) : 0.0138869285583
manual_with_catch_cache(work_fail) : 0.0213649272919
Các chi phí nhỏ hơn nhiều so với bạn tuyên bố. Hơn nữa, chỉ PyPy trên không dường như có thể loại bỏ tương đối so với try
... catch
cho biến thể thủ công là tạo đối tượng, được loại bỏ một cách trivially trong trường hợp này.
Thật không may with
is way too involved for good optimization by CPython, đặc biệt là liên quan đến contextlib
mà thậm chí PyPy thấy khó có thể tối ưu hóa. Điều này là bình thường OK bởi vì mặc dù tạo đối tượng + một cuộc gọi chức năng + tạo ra một máy phát điện là tốn kém, đó là giá rẻ so với những gì thường được thực hiện.
Nếu bạn là chắc chắn rằng with
đang gây ra phần lớn chi phí của bạn, hãy chuyển đổi người quản lý ngữ cảnh thành các thể hiện được lưu trong bộ nhớ cache như tôi có. Nếu vẫn còn quá nhiều chi phí, bạn có thể gặp vấn đề lớn hơn với cách thiết kế hệ thống của bạn. Xem xét việc làm cho phạm vi của các with
s lớn hơn (thường không phải là một ý tưởng tốt, nhưng chấp nhận được nếu cần).
Ngoài ra, PyPy. Dat JIT là nhanh.
Tôi không biết câu lệnh của bạn có đúng hay không, nhưng cộng đồng Python thường không quan tâm đến hiệu suất. –
@SiyuanRen "Tôi không biết nếu tuyên bố của bạn là đúng" đó là lý do tại sao tôi liên kết mã điểm chuẩn. Nó rất dễ chạy. – san
Tôi đã chạy và dường như xác thực điểm của bạn. Nhưng nhiều lần vấn đề là với điểm chuẩn hơn là hệ thống thực tế, mà tôi thấy trong khi cho rằng 'C++ quá chậm và điều này' quá nhiều lần. Tôi không phải là thạo trong Python để nói trong này. –