De Chromium Chronicle #1: best practices voor taakplanning

Het Chrome-team introduceert met trots de Chromium Chronicle, een maandelijkse serie die specifiek is gericht op Chromium-ontwikkelaars, ontwikkelaars die de browser bouwen.

De Chromium Chronicle zal zich vooral richten op het verspreiden van technische kennis en best practices voor het schrijven, bouwen en testen van Chrome. Het is ons plan om onderwerpen aan te bieden die relevant en nuttig zijn voor Chromium-ontwikkelaars, zoals codestatus, handige tools, testen van eenheden, toegankelijkheid en nog veel meer! Elk artikel wordt geschreven en bewerkt door Chrome-technici.

Wij zijn enthousiast over deze nieuwe serie en hopen dat jij dat ook bent! Klaar om erin te duiken? Bekijk hieronder onze eerste aflevering!

Beste praktijken voor taakplanning

Aflevering 1: door Gabriel Charette in Montréal, PQ (april 2019)
Vorige afleveringen

Chrome-code die asynchrone uitvoering tijdens het proces nodig heeft, plaatst taken doorgaans in reeksen. Reeksen zijn door Chrome beheerde 'virtuele threads' en verdienen de voorkeur boven het maken van uw eigen thread . Hoe weet een object in welke reeks het moet posten?

Niet doen

Het oude paradigma is om een ​​SequencedTaskRunner van de maker te ontvangen:

Foo::Foo(scoped_refptr backend_task_runner)
    : backend_task_runner_(std::move(backend_task_runner)) {}
Doen

Het voorkeursparadigma is het creëren van een onafhankelijke SequencedTaskRunner:

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

Dit is gemakkelijker te lezen en te schrijven omdat alle informatie lokaal is en er geen risico bestaat op onderlinge afhankelijkheid met niet-gerelateerde taken.

Dit paradigma is ook beter als het om testen gaat. In plaats van taaklopers handmatig te injecteren, kunnen tests een gecontroleerde taakomgeving creëren om de taken van Foo te beheren:

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

Door TaskEnvironment als eerste in het armatuur te hebben, wordt de taakomgeving gedurende de hele levensduur van Foo beheerd. De TaskEnvironment zal het verzoek van Foo tijdens de constructie vastleggen om een ​​SequencedTaskRunner te maken en zal de taken ervan onder elke FooTest beheren.

Om het resultaat van asynchrone uitvoering te testen, gebruikt u het RunLoop::Run()+QuitClosure() paradigma :

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

Dit heeft de voorkeur boven RunUntilIdle(), wat lastig kan zijn als de asynchrone werklast een taak betreft die buiten het bereik van de TaskEnvironment valt, bijvoorbeeld een systeemgebeurtenis. Gebruik RunUntilIdle() dus met zorg .

Wilt u meer weten? Lees onze documentatie over threading en taken of doe mee aan de migratie naar TaskEnvironment !