The Chromium Chronicle n. 1: best practice per la pianificazione delle attività

Il team di Chrome è orgoglioso di presentare Chromium Chronicle, una serie mensile pensata appositamente per gli sviluppatori Chromium, che realizzano i browser.

Chromium Chronicle si concentrerà principalmente sulla diffusione di conoscenze tecniche e best practice per scrivere, creare e testare Chrome. Il nostro piano prevede di presentare argomenti pertinenti e utili per gli sviluppatori di Chromium, come stato del codice, strumenti utili, test delle unità, accessibilità e molto altro. Ogni articolo sarà scritto e modificato dagli ingegneri di Chrome.

Siamo entusiasti di questa nuova serie e ci auguriamo che lo sia anche tu. Tutto pronto per iniziare? Dai un'occhiata al nostro primo episodio qui sotto.

Best practice per la pianificazione delle attività

Episodio 1: di Gabriel Charette a Montréal, PQ (aprile 2019)
Puntate precedenti

Il codice di Chrome che richiede l'esecuzione asincrona in-process di solito pubblica le attività nelle sequenze. Le sequenze sono "fili virtuali" gestiti da Chrome e sono preferiti per creare il proprio thread. Come fa un oggetto a sapere in quale sequenza pubblicare?

Cosa non fare

Il vecchio paradigma consiste nel ricevere un SequencedTaskRunner dal creatore:

Foo::Foo(scoped_refptr backend_task_runner)
    : backend_task_runner_(std::move(backend_task_runner)) {}
Cosa fare

Il paradigma preferito è creare un SequencedTaskRunner indipendente:

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

È più facile da leggere e scrivere poiché tutte le informazioni sono locali e non c'è alcun rischio di interdipendenza con attività non correlate.

Questo paradigma è migliore anche quando si tratta di test. Anziché inserire manualmente i runner, i test possono instaurare un ambiente di attività controllato per gestire le attività di Foo:

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

Avere TaskEnvironment prima nell'apparecchiatura garantisce naturalmente la gestione dell'ambiente delle attività per tutta la durata di Foo. TaskEnvironment acquisisce la richiesta di Foo durante la creazione per creare un SequencedTaskRunner e ne gestirà le attività in ogni FooTest.

Per testare il risultato dell'esecuzione asincrona, utilizza il paradigma RunLoop::Run()+QuitClosure():

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

Questa opzione è preferibile a RununtilIdle(), che può essere irregolare se il carico di lavoro asincrono prevede un'attività esterna all'ambito di TaskEnvironment, ad esempio un evento di sistema, quindi usa RunUntilIdle() con attenzione.

Vuoi saperne di più? Leggi la nostra documentazione su threading e attività o partecipa alla migrazione a TaskEnvironment.