c++ - C++ 上的并行并不像 C# 那样快
问题描述
我在C#上有这样的代码
private static Random random = new Random();
public static string RandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
Task.Factory.StartNew(() => {
System.Threading.Tasks.Parallel.For(0L, 10000000, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 }, n =>
{
Console.WirteLine(RandomString(12));
});
}
添加并行方法,它可以在不到 8 秒的时间内运行生成 1000 万个随机字符串并使用所有 CPU 功率
我尝试在C++中再做一次
string NonRepeatChar(int max_len)
{
std::string valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(valid_chars.begin(), valid_chars.end(), g);
std::string rand_str(valid_chars.begin(), valid_chars.begin() + max_len);
return rand_str;
}
将代码应用于一些推荐的C++并行方法
void multiply()
{
for (size_t i = 0; i < 10; i++)
{
for (size_t j = 0; j < 10; j++)
{
for (int k = 0; k < 10; k++)
{
printf("%s\n",NonRepeatChar(10));
}
}
}
}
class Foo {
public:
Foo() : counter_(0) {}
std::pair<string, std::future<void>> a_function(std::future<void>& f) {
// Ensure that the background task from the previous iteration
// has completed
f.wait();
// Set the task for the next iteration
std::future<void> fut = std::async(std::launch::async, &Foo::background_task, this);
// Do some work
string value = NonRepeatChar(12);
// Return the result and the future for the next iteration
return std::make_pair(value.c_str(), std::move(fut));
}
void background_task() {
++counter_;
}
private:
std::atomic<int> counter_;
};
记录运行时间
int main()
{
clock_t tStart = clock();
std::future<void> bleak = std::async(std::launch::deferred, []() {});
Foo foo;
for (size_t i = 0; i < 10000; ++i) {
// Call the function
std::pair<string, std::future<void>> result = foo.a_function(bleak);
bleak = std::move(result.second);
std::cout << result.first << "\n";
}
printf("Time taken: %.2fs\n", (double)(clock() - tStart) / CLOCKS_PER_SEC);
return 0;
}
这是我的结果:
10.98s//正常循环
8.76s//相乘
8.88s//Foo
显然代码与原始循环相比没有任何区别,仅生成 10000 行,甚至没有像C#那样使用所有 CPU 能力。并行方法有问题吗?我该如何优化它?
解决方案
您的 C++ 代码根本不等同于您的 C# 代码。
在 C# 方面,
您正在使用命名空间中Parallel.For
的a System.Threading.Tasks
。这是一个高级构造,它允许循环的迭代并行运行,而不必以低级方式控制线程,因为任务会自动为您创建并以最适合您的方式调度到您的处理器内核你的系统。
在您的特定代码的情况下,Parallel.For
配置为允许一次Environment.ProcessorCount * 10
安排最多的工作线程。虽然不能保证(库的调度程序将拥有最后的决定权),但这应该确保您的处理核心最佳地用于提交的工作负载,因为有足够的任务来占用所有核心,并且有足够大的工作队列来确保核心不会因为缺乏提前安排的工作而挨饿。
在 C++ 方面,
您正在使用async
and future
,它们是允许您运行后台任务的较低级别的构造,但是您通过在每次迭代中强制同步来人为地限制并行度:
// Ensure that the background task from the previous iteration
// has completed
f.wait();
在 C++ 中实现与 C# 代码类似的行为的最简单(但不可移植)方法是使用 Microsoft 的Parallel Patterns Library。这提供了System.Threading.Tasks.Parallel.For
与 C# 端提供的功能非常相似的功能,即concurrency::parallel_for
.
推荐阅读
- html - 动画变化的背景
- subset-sum - 集划分问题的 NP 完备性证明
- python - 多多边形三角形网格/网格与python中的形状
- asp.net - 执行失败:javax.ws.rs.NotFoundException:
- android-intent - ACTION_HEADSET_PLUG 不工作 API Lollipop
- google-api - 为什么无法使用 .NET Google Admin SDK 客户端库列出用户或组
- javascript - 用 document.write 替换页面内容后无法刷新
- python - 使用 openpyxl 附加一个 excel 文件
- configuration - Spring Batch步骤配置:无限循环
- javascript - 滚动捕捉元素的孙子 - CSS & React Router 模式