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 herramienta dirigida específicamente a los desarrolladores de Chromium, los desarrolladores que crean navegador.

Chromium Chronicle se centrará principalmente en difundir el conocimiento técnico y las prácticas recomendadas para escribir, compilar y probar Chrome. Nuestro plan es presentar temas que son relevantes y útiles para los desarrolladores de Chromium, como el código salud, herramientas útiles, prueba de unidades, accesibilidad y mucho más. Cada artículo serán escritas y editadas por ingenieros de Chrome.

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

Prácticas recomendadas para la programación de tareas

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

Por lo general, el código de Chrome que necesita una ejecución asíncrona en proceso publica tareas en secuencias. Las secuencias son "subprocesos virtuales" administrados por Chrome y son preferiste crear tu propia conversación. ¿Cómo hace un objeto saber en qué secuencia publicar?

Qué no debes hacer

El paradigma antiguo consiste en recibir un SequencedTaskRunner del creador:

Foo::Foo(scoped_refptr backend_task_runner)
    : backend_task_runner_(std::move(backend_task_runner)) {}
Qué debes hacer

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 no hay riesgo de interdependencia con tareas no relacionadas.

Este paradigma también es mejor cuando se trata de pruebas. En lugar de inyectar manualmente los ejecutores de tareas, las pruebas pueden crear una instancia de un entorno de tareas controlado 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 naturalmente que administra el entorno de tareas durante la vida de Foo. El TaskEnvironment capturará la solicitud en construcción de Foo para crear un elemento SequencedTaskRunner y administrará sus 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());
}

Se prefiere a RunUntilIdle(), que puede ser inestable si la función de trabajo implica una tarea fuera del ámbito de TaskEnvironment, p.ej., un evento del sistema, por lo que debes usar RunUntilIdle() con cuidado.

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