Chromium Chronicle n°1: bonnes pratiques de planification des tâches

L'équipe Chrome est fière de vous présenter Chromium Chronicle, une série mensuelle spécialement conçue pour les développeurs Chromium, qui créent le navigateur.

Chromium Chronicle se concentre principalement sur la diffusion de connaissances techniques et de bonnes pratiques pour écrire, compiler et tester Chrome. Nous prévoyons de mettre en avant des sujets pertinents et utiles pour les développeurs Chromium, tels que l'état du code, des outils pratiques, les tests unitaires, l'accessibilité et bien plus encore. Chaque article sera rédigé et édité par des ingénieurs Chrome.

Nous avons hâte de découvrir cette nouvelle série et nous espérons que vous aussi ! Prêt à vous lancer ? Découvrez notre premier épisode ci-dessous.

Bonnes pratiques de planification des tâches

Épisode 1:Gabriel Charette à Montréal, PQ (avril 2019)
Épisodes précédents

Le code Chrome nécessitant une exécution asynchrone en cours de traitement publie généralement des tâches dans des séquences. Les séquences sont des "threads virtuels" gérés par Chrome et sont préférables pour créer votre propre thread. Comment un objet sait-il dans quelle séquence publier ?

À éviter

L'ancien paradigme consiste à recevoir un SequencedTaskRunner de la part du créateur:

Foo::Foo(scoped_refptr backend_task_runner)
    : backend_task_runner_(std::move(backend_task_runner)) {}
À faire

Le paradigme privilégié consiste à créer un SequencedTaskRunner indépendant:

Foo::Foo()
    : backend_task_runner_(
          base::CreateSequencedTaskRunnerWithTraits({
              base::MayBlock(), base::TaskPriority::BEST_EFFORT})) {}

Cette méthode est plus facile à lire et à écrire, car toutes les informations sont locales et il n'y a aucun risque d'interdépendance avec des tâches non liées.

Ce paradigme est également préférable pour les tests. Au lieu d'injecter manuellement des exécuteurs de tâches, les tests peuvent instancier un environnement de tâches contrôlé pour gérer les tâches de Foo:

class FooTest : public testing::Test {
 public
  (...)
 protected:
  base::test::TaskEnvironment task_environment_;
  Foo foo_;
};

L'utilisation de TaskEnvironment en premier dans l'équipement permet naturellement de gérer l'environnement des tâches tout au long de la durée de vie de Foo. TaskEnvironment capture la requête en cours de construction de Foo pour créer un SequencedTaskRunner et gère ses tâches sous chaque FooTest.

Pour tester le résultat de l'exécution asynchrone, utilisez le paradigme RunLoop::Run()+QuitClosure():

TEST_F(FooTest, TestAsyncWork) {
  RunLoop run_loop;
  foo_.BeginAsyncWork(run_loop.QuitClosure());
  run_loop.Run();
  EXPECT_TRUE(foo_.work_done());
}

Il est préférable d'utiliser RunJusqu'Idle(), qui peut être instable si la charge de travail asynchrone implique une tâche qui n'est pas du ressort de TaskEnvironment, par exemple un événement système. Veillez donc à utiliser RunUntilIdle() avec précaution.

Envie d'en savoir plus ? Consultez notre documentation sur les threads et les tâches ou participez à la migration vers TaskEnvironment.