我注意到在运行以下代码时,向量比bool数组慢得多。
TASK [Installation of <application_name>] ************************************************
task path: /var/lib/awx/projects/tests/<file>.yml:6
fatal: [xxx.163.xxx.69]: FAILED! => {"changed": false, "failed": true, "rc": 1, "stderr": "", "stdout": "", "stdout_lines": []}
NO MORE HOSTS LEFT *************************************************************
[ERROR]: Could not create retry file '<file>_bat.retry'. The error was: [Errno
13] Permission denied: '<file>_bat.retry'
我能采取哪些方法让int main()
{
int count = 0;
int n = 1500000;
// slower with c++ vector<bool>
/*vector<bool> isPrime;
isPrime.reserve(n);
isPrime.assign(n, true);
*/
// faster with bool array
bool* isPrime = new bool[n];
for (int i = 0; i < n; ++i)
isPrime[i] = true;
for (int i = 2; i< n; ++i) {
if (isPrime[i])
count++;
for (int j =2; i*j < n; ++j )
isPrime[i*j] = false;
}
cout << count << endl;
return 0;
}
更快?顺便说一句,vector<bool>
和std::vector::push_back
都比std::vector::emplace_back
慢。
答案 0 :(得分:14)
std::vector<bool>
可能会遇到各种性能问题(例如,请查看https://isocpp.org/blog/2012/11/on-vectorbool)。
一般来说,你可以:
使用std::vector<std::uint8_t>
代替std::vector<bool>
(也尝试std::valarray<bool>
)。
这需要更多的内存并且对缓存不太友好,但是没有开销(以位操作的形式)来访问单个值,因此在某些情况下它可以更好地工作(毕竟它就像你的数组bool
,但没有内存管理的麻烦)
std::bitset
boost::dynamic_bitset
(可以在运行时指定大小)但是对于速度优化,你必须测试......
通过您的具体示例,我可以仅在关闭优化时确认性能差异(当然这不是可行的方法)。
在英特尔至强系统(-O3
优化级别)上使用g ++ v4.8.3和clang ++ v3.4.5进行的一些测试给出了不同的图片:
time (ms)
G++ CLANG++
array of bool 3103 3010
vector<bool> 2835 2420 // not bad!
vector<char> 3136 3031 // same as array of bool
bitset 2742 2388 // marginally better
(答案中100次运行代码的时间已过去)
std::vector<bool>
看起来不那么糟糕(源代码here)。
答案 1 :(得分:10)
vector<bool>
可能具有模板特化,可以使用位数组来实现以节省空间。提取并保存一点并将其从/转换为bool
可能会导致您观察到的性能下降。如果您使用std::vector::push_back
,则会调整向量的大小,从而导致性能下降。下一个性能杀手可能是assign
(最差复杂性:第一个参数的线性),而是使用operator []
(复杂性:常量)。
另一方面,bool []
保证为bool
的数组。
您应该调整为n
而不是n-1
以避免未定义的行为。
答案 2 :(得分:5)
vector<bool>
可以高性能,但不是必须的。要使vector<bool>
有效,它需要一次操作许多bool(例如isPrime.assign(n, true)
),和,实现者必须对其进行爱护。将单个bool索引为vector<bool>
的速度很慢。
这是一个使用vector<bool>
和clang + libc ++(libc ++部分很重要)的一段时间的主要发现者:
#include <algorithm>
#include <chrono>
#include <iostream>
#include <vector>
std::vector<bool>
init_primes()
{
std::vector<bool> primes(0x80000000, true);
primes[0] = false;
primes[1] = false;
const auto pb = primes.begin();
const auto pe = primes.end();
const auto sz = primes.size();
size_t i = 2;
while (true)
{
size_t j = i*i;
if (j >= sz)
break;
do
{
primes[j] = false;
j += i;
} while (j < sz);
i = std::find(pb + (i+1), pe, true) - pb;
}
return primes;
}
int
main()
{
using namespace std::chrono;
using dsec = duration<double>;
auto t0 = steady_clock::now();
auto p = init_primes();
auto t1 = steady_clock::now();
std::cout << dsec(t1-t0).count() << "\n";
}
这在大约28s(-O3)中为我执行。当我将其更改为返回vector<char>
时,执行时间会上升到大约44秒。
如果你使用其他一些std :: lib运行它,你可能不会看到这种趋势。在libc ++上,std::find
等算法已经过优化,可以一次搜索一个字位,而不是一次搜索一位。
有关供应商可以优化哪些std算法的更多详细信息,请参阅http://howardhinnant.github.io/onvectorbool.html。