大家好,今天小白給大家簡單分享下Hetcompute sdk中task相關的基礎知識,歡迎一起交流學習。
一、什麼是task
Task 是異步執行的基礎機關。具體來說,任務是一個獨立的工作單元,它可以在 CPU、GPU、DSP 上異步執行。
任務将計算和資料綁定,包含控制和資料兩部分。控制部分可以是一個 C++ 函數,一個(前述) Kernel,或一個模式等;
資料部分則可以是緩沖區、函數參數等。
二、如何建立以及啟動task
1、使用Lambda表達式建立任務
Lambda表達式是C ++ 11中的一個新功能,也是建立hetcompute任務的首選參數類型,能夠從封閉的範圍中捕獲變量。
以下代碼使用lambda表達式建立一個列印“Hello World!”的任務t1。
#include <hetcompute/hetcompute.hh>
int main()
{
hetcompute::runtime::init();
// Create a task that prints Hello World!
auto t1 = hetcompute::create_task([] { HETCOMPUTE_ILOG("Hello World!\n"); });
// Launch the task.
t1->launch();
// Wait for the task to finish.
t1->wait_for();
hetcompute::runtime::shutdown();
return 0;
}
或者,可以使用hetcompute::launch(...) or hetcompute::group::launch(...).
上面的示例中沒有捕獲變量,假設您想要使用name捕獲字元串以進行正确的通路:
#include <hetcompute/hetcompute.hh>
int main()
{
hetcompute::runtime::init();
auto g = hetcompute::create_group();
std::string name = "HETCOMPUTE";
// Launching a task in the group.
g->launch([name] { HETCOMPUTE_ILOG("Hello World, %s!\n", name.c_str()); });
// Wait for g to finish.
g->wait_for();
hetcompute::runtime::shutdown();
return 0;
}
2、使用類建立任務
您可以通過重載類的operator()來将任何自定義類用作<typename Code>。 以下代碼顯示如何從類執行個體建立任務。 當HetCompute排程程式執行時任務,調用operator()方法。
#include <hetcompute/hetcompute.hh>
class user_class
{
public:
explicit user_class(int value) : x(value) {}
void operator()(int y) { HETCOMPUTE_ILOG("x = %d, y = %d\n", x, y); }
void set_x(int value) { x = value; }
private:
int x;
}
int main()
{
hetcompute::runtime::init();
auto g = hetcompute::create_group();
g->launch(user_class(42), 27); // a行
// Wait for the group to finish.
g->wait_for();
hetcompute::runtime::shutdown();
return 0;
}
也可以将a行替換為:user_class obj(42); auto t = hetcompute::create_task(obj); g->launch(t, 27);
3、使用函數指針建立任務
最後一種建立任務的方法是通過函數指針;
#include <hetcompute/hetcompute.hh>
void foo();
void foo()
{
HETCOMPUTE_ILOG("Hello World!\n");
}
int main()
{
hetcompute::runtime::init();
// Create a task that executes foo().
//auto t = hetcompute::create_task(foo); 由于Visual Studio C ++編譯器的限制,這在Visual Studio上不起作用。 你可以使用 // lambda函數繞過它.
auto t = hetcompute::create_task([] { foo(); });
// Launch and wait for the task.
t->launch();
t->wait_for();
hetcompute::runtime::shutdown();
return 0;
}
三、task的依賴介紹
HetCompute提供了一種指定任務之間的控制和資料依賴性的方法。 程式員可以統一的方式建構跨越CPU,GPU和DSP的豐富的非循環任務圖。 任務可以在任務圖中具有多個前驅和後繼。 隻有在所有(控制和資料相關性)前驅成功完成後,任務才可以執行。
1、Control Dependencies
可以使用hetcompute :: task <> :: then()在任務之間建立控制依賴關系,以指定任務執行的相對順序。 以下示例顯示如何確定任務t1在任務t2之前執行。
#include <hetcompute/hetcompute.hh>
int main()
{
hetcompute::runtime::init();
auto t1 = hetcompute::create_task([] { HETCOMPUTE_ILOG("Hello "); });
auto t2 = hetcompute::create_task([] { HETCOMPUTE_ILOG("World!"); });
// Ensure that t1 executes before t2
t1->then(t2);
t1->launch();
t2->launch();
t2->wait_for();
hetcompute::runtime::shutdown();
return 0;
}
在上面的示例中,語句t1-> then(t2)保證t1在t2開始執行之前結束。 是以,隻需等待t2完成以確定t1和t2都完成即可。
2、Data Dependencies
任務t2可以依賴于另一個任務t1的資料,如下例所示:
#include <hetcompute/hetcompute.hh>
int main()
{
hetcompute::runtime::init();
auto t1 = hetcompute::create_task([] { return 42; });
auto t2 = hetcompute::create_task([](int i) { HETCOMPUTE_ILOG("The answer to life the universe and everything = %d", i); });
// Set up data dependency from t1 to t2
t2->bind_all(t1);
t1->launch();
t2->launch();
t2->wait_for();
hetcompute::runtime::shutdown();
return 0;
}
四、task的生命周期
一個任務通過使用hetcompute::create_task(Code&&), hetcompute::launch(Code&&), etc來建立,至少有一個hetcompute::task_ptr<>指針存在于使用者代碼中,它可以用來對任務執行操作,綠線狀态切換如下描述:
1、在建立控制依賴或者資料依賴之後,使用hetcompute::task<>::launch()來注冊任務到HetCompute運作時系統,并且不會向已啟動的任務添加其他依賴項。
2、在任務控制或資料相關的所有任務都已轉換為“已完成”後,任務将變為Ready狀态。
3、當執行資源(CPU,GPU或DSP)變得可用且任務可能使用的任何其他資源(如hetcompute :: buffers)變為可用時,任務将轉換為Running狀态。
4、最後在任務成功執行之後,任務轉換為Completed狀态。
紅線狀态切換如下:
5、如果通過hetcompute :: task <> :: cancel()取消了控制或資料相關的任務或任何任務,則任務将轉換為“已取消”狀态。(同理6、7、8)
9、某些建立的任務可能永遠不會啟動,當最後一次hetcompute :: task_ptr <>指向這樣的任務超出範圍,任務自動取消。任何後續任務也會被取消。
五、總結
本篇主要簡單介紹了hetcompute sdk中建立task的三種方法、任務之間的依賴(包括控制依賴和資料依賴)以及任務的生命周期,歡迎一起交流學習。