在iOS设备上执行并发任务时如何设置正确的线程数?

How do you set the proper number of threads when executing concurrency task on iOS device?

本文关键字:设置 线程 何设置 iOS 执行 并发 任务      更新时间:2023-10-16

我开发了一个跨平台的c++库,它在运行时生成线程。 我使用并发队列来调度计算任务,因此每个线程在大部分时间都会很忙。

现在的问题是如何在运行时获得适当数量的线程。由于我的任务没有 I/O 或网络操作,只有计算和堆内存分配,因此最佳策略是每个 CPU 内核生成线程:

我的代码如下所示:

#include "concurrentqueue.h"
#include <algorithm>
#include <thread>
#include <vector>
#include <iostream>
#include <mutex>
std::mutex io_m;
struct Task {
int n;
};
void some_time_consuming_operations(Task &t) {
std::vector<int> vec;
for (int i = 0; i < t.n; ++i)
vec.push_back(1);
{
std::lock_guard<std::mutex> g(io_m);
std::cout << "thread " << std::this_thread::get_id() << " done, vec size:" << vec.size() << std::endl;
}
}
int main() {
// moodycamel's lockfree queue: https://github.com/cameron314/concurrentqueue
moodycamel::ConcurrentQueue<Task> tasks;
for (int i = 0; i < 100; ++i)
tasks.enqueue(Task{(i % 5) * 1000000 + 1000000});
// I left 2 threads for ui and other usages
std::vector<std::thread> jobs(std::max((size_t)2, (size_t)std::thread::hardware_concurrency() - 2));
std::cout << "thread num:" << jobs.size() << std::endl;
for (auto &job : jobs) {
job = std::thread([&tasks]() {
Task task;
while (tasks.try_dequeue(task))
some_time_consuming_operations(task);
});
}
for (auto &job : jobs)
job.join();
return 0;
}

但是,在我的iOS设备(iPhone XR,A12)上启用多线程时,测试程序比单线程模式慢2倍。我已经在带有 4 核 8 线程英特尔 CPU 的 My Windows 机器上对其进行了测试,它比单线程模式快 6 倍。

在我的iPhone上,hardware_concurrency函数返回6,这是Apple A12的核心数字。在我的窗口机器上,这个数字是 8。

我知道有 4 个节能内核称为 Tempest 谎言 i 苹果的 A12,但由于他们声称 A11/A12 将同时使用所有六个内核(我在测试期间保持充电)。我不知道为什么它比单线程模式慢。

测试程序是由UE4构建的游戏应用程序。

四个较慢的核心比快速核心慢得多。因此,如果您在快速内核上执行一项需要 6 秒的任务,并在每个内核上运行一秒钟的工作,那么两个快速内核将在一秒钟后完成,而四个慢速内核可能需要 10 秒。

如果您使用 GCD,iOS 会在内核之间随机排列这六个线程,因此您可以获得高达 2.4 倍的速度。如果你的线程实现不这样做,那么你正在减慢速度。

解决方案:要么使用 GCD(并获得 2.4 的加速比),要么只使用两个线程(并获得 2.0 的加速比)。那是在iPhone XR上;您需要以某种方式找出快速内核的数量。