Chromium Chronicle #1:安排工作排程的最佳做法

Chrome 團隊很高興能向大家介紹 Chromium Chronicle,這是針對建構瀏覽器的 Chromium 開發人員,每月專為 Chromium 開發人員打造的系列。

Chromium Chronicle 的重點在於傳播技術知識和最佳做法,讓您順利編寫、建構及測試 Chrome。我們打算針對 Chromium 開發人員提供相關且實用的主題,例如程式碼健康狀態、實用工具、單元測試、無障礙等等!每篇文章都會由 Chrome 工程師撰寫及編輯。

希望你也能收看這個新的系列影片!準備好探索地球了嗎? 請觀看下方的第一集!

工作排程最佳做法

第 1 集:Gabriel Charette 在蒙特婁,PQ (2019 年 4 月)
先前劇集

需要處理中非同步執行的 Chrome 程式碼通常會將工作發布至序列。序列是由 Chrome 管理的「虛擬執行緒」,建議您建立自己的執行緒。物件如何得知要張貼到哪個序列?

錯誤做法

舊的模式是取得建立者的 SequencedTaskRunner:

Foo::Foo(scoped_refptr backend_task_runner)
    : backend_task_runner_(std::move(backend_task_runner)) {}
正確做法

建議的模式為建立獨立的 SequencedTaskRunner:

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

因為所有資訊均位於本機,而且不會與不相關的工作發生依附性,所以讀取及寫入更容易。

此外,這個模式在測試時也更加完善。相較於手動插入工作執行器,測試可以將受控管的工作環境執行個體化來管理 Foo 的工作:

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

TaskEnvironment 優先於固件,確保其能在整個 Foo 的生命週期中管理工作環境。TaskEnvironment 會擷取 Foo 的建構要求,建立 SequencedTaskRunner,並會在每個 FooTest 下管理其工作。

如要測試非同步執行的結果,請使用 RunLoop::Run()+QuitClosure() 模式

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

偏好使用 RunUntilIdle(),如果非同步工作負載涉及 TaskEnvironment 的 Puview 以外的工作 (例如系統事件) 以外的工作 (例如系統事件),這可能會產生不穩定的問題,因此請謹慎使用 RunUntilIdle()

想瞭解更多資訊嗎?請參閱有關執行緒和工作的說明文件,或參與遷移至工作環境