在c++/java/python 等语言中,我们可以选择throw关键词来抛出异常,在c++中它遇到throw时,编译器要生成一些代码来存储堆栈信息,其次运行时如果遇到异常也需要内存中记录一些上下文堆栈信息,导致函数性能劣化严重!
测试
#include <benchmark/benchmark.h>
#include <cstdlib>
#include <outcome.hpp>
#include <stdexcept>
#include <string>
#include <system_error>
namespace outcome = OUTCOME_V2_NAMESPACE;
// 使用 exception
static std::string to_string(int num) {
if (num > 100) {
throw std::invalid_argument("");
}
return std::to_string(num);
}
// 使用 outcome::result
static outcome::result<std::string> to_string_no_excpt(int num) noexcept {
if (num > 100) {
return outcome::failure(std::errc::invalid_argument);
}
return std::to_string(num);
}
// 使用 c 标准写法,把输出参数放到输入上
static int to_string_std(int num, std::string& output) noexcept {
if (num > 100) {
return -1;
}
output.append(std::to_string(num));
return 0;
}
static void test_exception(benchmark::State& state) {
for (auto _ : state) {
try {
auto x = to_string(std::rand());
} catch (...) {
}
}
}
static void test_noexception(benchmark::State& state) {
for (auto _ : state) {
auto x = to_string_no_excpt(std::rand());
if (x) {
x.value(); // todo
} else {
x.error(); // todo
}
}
}
static void test_noexception_std(benchmark::State& state) {
for (auto _ : state) {
std::string output;
auto x = to_string_std(std::rand(), output);
if (x) {
// todo
}
}
}
BENCHMARK(test_exception);
BENCHMARK(test_noexception);
BENCHMARK(test_noexception_std);
BENCHMARK_MAIN();
测试开启-O2优化测试两次的结果,发现throw exception 性能劣化非常严重!
---------------------------------------------------------------
Benchmark Time CPU Iterations
---------------------------------------------------------------
test_exception 3517 ns 3211 ns 218450
test_noexception 6.05 ns 5.98 ns 117859007
test_noexception_std 6.01 ns 5.93 ns 113924875
---------------------------------------------------------------
test_exception 3254 ns 3200 ns 213889
test_noexception 6.05 ns 5.98 ns 116138238
test_noexception_std 6.04 ns 5.97 ns 116865338
那么假如我们代码干脆就没有异常,都走不到except里,测试下其实性能三者差距不大!
---------------------------------------------------------------
test_exception 12.7 ns 11.8 ns 58565644
test_noexception 13.3 ns 13.1 ns 53467767
test_noexception_std 19.0 ns 18.8 ns 36429872
---------------------------------------------------------------
test_exception 11.9 ns 11.7 ns 60039454
test_noexception 15.5 ns 13.2 ns 53046780
test_noexception_std 19.7 ns 19.2 ns 36500537
结论
代码中经可能少的使用 throw exception,可以使用 c写法 或者 使用outcome::result 库,来避免大量throw exception带来的性能劣化!