Chromium Chronicle n.o 1: Prácticas recomendadas para la programación de tareas

El equipo de Chrome se enorgullece en presentar Chromium Chronicle, una serie mensual diseñada específicamente para desarrolladores de Chromium que compilan el navegador.

Chromium Chronicle se enfocará principalmente en difundir conocimiento técnico y prácticas recomendadas para escribir, compilar y probar Chrome. Nuestro plan es incluir temas que sean relevantes y útiles para los desarrolladores de Chromium, como el estado del código, herramientas útiles, pruebas de unidades, accesibilidad y mucho más. Ingenieros de Chrome escribirán y editarán cada artículo.

Nos entusiasma esta nueva serie y esperamos que a ti también. ¿Todo listo para comenzar? Mira nuestro primer episodio a continuación.

Prácticas recomendadas para la programación de tareas

Episodio 1: de Gabriel Charette en Montreal, PQ (abril de 2019)
Episodios anteriores

El código de Chrome que necesita ejecución asíncrona en proceso suele publicar tareas en secuencias. Las secuencias son "subprocesos virtuales" que administra Chrome y se preferen crear tu propio subproceso. ¿Cómo sabe un objeto en qué secuencia publicar?

Qué no debes hacer

El paradigma anterior era recibir un SequencedTaskRunner del creador:

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

El paradigma preferido es crear un SequencedTaskRunner independiente:

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

Esto es más fácil de leer y escribir, ya que toda la información es local y no hay riesgo de interdependencia con tareas no relacionadas.

Este paradigma también es mejor cuando se trata de pruebas. En lugar de insertar ejecutores de tareas de forma manual, las pruebas pueden crear una instancia de un entorno de tareas controlados para administrar las tareas de Foo:

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

Tener TaskEnvironment primero en el dispositivo garantiza que se administre el entorno de la tarea durante todo el ciclo de vida de Foo. TaskEnvironment capturará la solicitud en construcción de Foo para crear un SequencedTaskRunner y administrará las tareas en cada FooTest.

Para probar el resultado de la ejecución asíncrona, usa el paradigma RunLoop::Run()+QuitClosure():

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

Esto es preferible a RunUntilIdle(), que puede ser inestable si la carga de trabajo asíncrona implica una tarea fuera del ámbito de TaskEnvironment (p.ej., un evento del sistema), así que usa RunUntilIdle() con cuidado.

¿Quieres obtener más información? Lee nuestra documentación sobre subprocesos y tareas, o participa en la migración a TaskEnvironment.