Hetcompute sdk中的task介绍
大家好,今天小白给大家简单分享下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的三种方法、任务之间的依赖(包括控制依赖和数据依赖)以及任务的生命周期,欢迎一起交流学习。