Chromium Chronicle #1: Praktik Terbaik Penjadwalan Tugas

Dengan bangga tim Chrome memperkenalkan Chromium Chronicle, rangkaian bulanan yang ditujukan khusus untuk developer Chromium dan developer yang membuat browser.

Chromium Chronicle terutama akan berfokus pada penyebaran pengetahuan teknis dan praktik terbaik untuk menulis, membuat, dan menguji Chrome. Rencana kami adalah menampilkan topik yang relevan dan berguna bagi developer Chromium, seperti kesehatan kode, alat yang bermanfaat, pengujian unit, aksesibilitas, dan banyak lagi. Setiap artikel akan ditulis dan diedit oleh engineer Chrome.

Kami sangat senang dengan serial baru ini, dan semoga Anda juga demikian! Siap untuk memulai? Tonton episode pertama kami di bawah ini.

Praktik Terbaik Penjadwalan Tugas

Episode 1: oleh Gabriel Charette di Montréal, PQ (April, 2019)
Episode sebelumnya

Kode Chrome yang memerlukan eksekusi asinkron dalam proses biasanya memposting tugas ke urutan. Urutan adalah "thread virtual" yang dikelola Chrome dan lebih disarankan untuk membuat thread Anda sendiri. Bagaimana suatu objek mengetahui urutan mana yang harus di-posting?

Larangan

Paradigma lama adalah menerima SequencedTaskRunner dari kreator:

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

Paradigma yang disukai adalah membuat SequencedTaskRunner independen:

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

Hal ini lebih mudah dibaca dan ditulis karena semua informasi bersifat lokal dan tidak ada risiko antar-dependensi dengan tugas yang tidak terkait.

Paradigma ini juga lebih baik dalam hal pengujian. Daripada memasukkan task runner secara manual, pengujian dapat membuat instance lingkungan tugas yang terkontrol untuk mengelola tugas Foo:

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

Memiliki TaskEnvironment terlebih dahulu di perlengkapan secara alami memastikannya mengelola lingkungan tugas sepanjang masa penggunaan Foo. TaskEnvironment akan merekam permintaan konstruksi Foo untuk membuat SequencedTaskRunner dan akan mengelola tugasnya pada setiap FooTest.

Untuk menguji hasil eksekusi asinkron, gunakan paradigma RunLoop::Run()+QuitClosure():

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

Opsi ini lebih disarankan untuk RunBeforeIdle(), yang dapat tidak stabil jika beban kerja asinkron melibatkan tugas di luar cakupan TaskEnvironment, misalnya peristiwa sistem, jadi gunakan RunUntilIdle() dengan hati-hati.

Ingin mempelajari lebih lanjut? Baca dokumentasi kami tentang threading dan tugas atau ikut terlibat dalam migrasi ke TaskEnvironment.