Команда Chrome с гордостью представляет ежемесячную серию Chromium Chronicle, специально предназначенную для разработчиков Chromium, разработчиков, создающих браузер.
Chromium Chronicle в первую очередь сосредоточится на распространении технических знаний и лучших практик написания, сборки и тестирования Chrome. Наш план — освещать темы, которые актуальны и полезны для разработчиков Chromium, такие как работоспособность кода, полезные инструменты, модульное тестирование, специальные возможности и многое другое! Каждая статья будет написана и отредактирована инженерами Chrome.
Мы в восторге от этой новой серии и надеемся, что вы тоже! Готовы погрузиться? Посмотрите наш первый выпуск ниже!
Лучшие практики планирования задач
Эпизод 1: Габриэль Шаретт, Монреаль, PQ (апрель 2019 г.)
Предыдущие серии
Код Chrome, требующий асинхронного выполнения внутри процесса, обычно помещает задачи в последовательности. Последовательности представляют собой «виртуальные потоки», управляемые Chrome, и их предпочтительнее создавать собственные потоки . Как объект узнает, в какую последовательность отправлять сообщения?
Старая парадигма — получить SequencedTaskRunner от создателя:
Foo::Foo(scoped_refptr<base::SequencedTaskRunner> backend_task_runner) : backend_task_runner_(std::move(backend_task_runner)) {}
Предпочтительной парадигмой является создание независимого SequencedTaskRunner:
Foo::Foo() : backend_task_runner_( base::CreateSequencedTaskRunnerWithTraits({ base::MayBlock(), base::TaskPriority::BEST_EFFORT})) {}
Его легче читать и писать, поскольку вся информация локальна и нет риска взаимозависимости с несвязанными задачами.
Эта парадигма также лучше, когда дело доходит до тестирования. Вместо того, чтобы вручную внедрять средства запуска задач, тесты могут создавать экземпляры контролируемой среды задач для управления задачами Foo:
class FooTest : public testing::Test {
public
(...)
protected:
base::test::TaskEnvironment task_environment_;
Foo foo_;
};
Наличие TaskEnvironment первым в приспособлении, естественно, гарантирует, что он управляет средой задач на протяжении всей жизни Foo. TaskEnvironment будет захватывать запрос при построении Foo для создания SequencedTaskRunner и будет управлять его задачами в рамках каждого FooTest.
Чтобы проверить результат асинхронного выполнения, используйте парадигму RunLoop::Run()+QuitClosure()
:
TEST_F(FooTest, TestAsyncWork) {
RunLoop run_loop;
foo_.BeginAsyncWork(run_loop.QuitClosure());
run_loop.Run();
EXPECT_TRUE(foo_.work_done());
}
Это предпочтительнее, чем RunUntilIdle(), который может быть нестабильным, если асинхронная рабочая нагрузка включает в себя задачу, находящуюся за пределами компетенции TaskEnvironment, например системное событие, поэтому используйте RunUntilIdle()
с осторожностью .
Хотите узнать больше? Прочтите нашу документацию по многопоточности и задачам или примите участие в переходе на TaskEnvironment !