Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 505a825

Browse files
added dependent_async overloads
1 parent 6946eb4 commit 505a825

File tree

4 files changed

+270
-13
lines changed

4 files changed

+270
-13
lines changed

examples/dependent_async.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ int main(){
66

77
// demonstration of dependent async (with future)
88
printf("Dependent Async\n");
9-
auto [A, fuA] = executor.dependent_async("A", [](){ printf("A\n"); });
10-
auto [B, fuB] = executor.dependent_async("B", [](){ printf("B\n"); }, A);
11-
auto [C, fuC] = executor.dependent_async("C", [](){ printf("C\n"); }, A);
12-
auto [D, fuD] = executor.dependent_async("D", [](){ printf("D\n"); }, B, C);
9+
auto [A, fuA] = executor.dependent_async([](){ printf("A\n"); });
10+
auto [B, fuB] = executor.dependent_async([](){ printf("B\n"); }, A);
11+
auto [C, fuC] = executor.dependent_async([](){ printf("C\n"); }, A);
12+
auto [D, fuD] = executor.dependent_async([](){ printf("D\n"); }, B, C);
1313

1414
fuD.get();
1515

1616
// demonstration of silent dependent async (without future)
1717
printf("Silent Dependent Async\n");
18-
A = executor.silent_dependent_async("A", [](){ printf("A\n"); });
19-
B = executor.silent_dependent_async("B", [](){ printf("B\n"); }, A);
20-
C = executor.silent_dependent_async("C", [](){ printf("C\n"); }, A);
21-
D = executor.silent_dependent_async("D", [](){ printf("D\n"); }, B, C);
18+
A = executor.silent_dependent_async([](){ printf("A\n"); });
19+
B = executor.silent_dependent_async([](){ printf("B\n"); }, A);
20+
C = executor.silent_dependent_async([](){ printf("C\n"); }, A);
21+
D = executor.silent_dependent_async([](){ printf("D\n"); }, B, C);
2222

2323
executor.wait_for_all();
2424

taskflow/core/async.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ namespace tf {
1010
// Silent Dependent Async
1111
// ----------------------------------------------------------------------------
1212

13+
// Function: silent_dependent_async
14+
template <typename F, typename... Tasks,
15+
std::enable_if_t<all_same_v<AsyncTask, std::decay_t<Tasks>...>, void>*
16+
>
17+
tf::AsyncTask Executor::silent_dependent_async(F&& func, Tasks&&... tasks) {
18+
return silent_dependent_async("", std::forward<F>(func), std::forward<Tasks>(tasks)...);
19+
}
20+
1321
// Function: silent_dependent_async
1422
template <typename F, typename... Tasks,
1523
std::enable_if_t<all_same_v<AsyncTask, std::decay_t<Tasks>...>, void>*
@@ -51,6 +59,14 @@ tf::AsyncTask Executor::silent_dependent_async(
5159
return AsyncTask(std::move(node));
5260
}
5361

62+
// Function: silent_dependent_async
63+
template <typename F, typename I,
64+
std::enable_if_t<!std::is_same_v<std::decay_t<I>, AsyncTask>, void>*
65+
>
66+
tf::AsyncTask Executor::silent_dependent_async(F&& func, I first, I last) {
67+
return silent_dependent_async("", std::forward<F>(func), first, last);
68+
}
69+
5470
// Function: silent_dependent_async
5571
template <typename F, typename I,
5672
std::enable_if_t<!std::is_same_v<std::decay_t<I>, AsyncTask>, void>*
@@ -96,6 +112,14 @@ tf::AsyncTask Executor::silent_dependent_async(
96112
// Dependent Async
97113
// ----------------------------------------------------------------------------
98114

115+
// Function: dependent_async
116+
template <typename F, typename... Tasks,
117+
std::enable_if_t<all_same_v<AsyncTask, std::decay_t<Tasks>...>, void>*
118+
>
119+
auto Executor::dependent_async(F&& func, Tasks&&... tasks) {
120+
return dependent_async("", std::forward<F>(func), std::forward<Tasks>(tasks)...);
121+
}
122+
99123
// Function: dependent_async
100124
template <typename F, typename... Tasks,
101125
std::enable_if_t<all_same_v<AsyncTask, std::decay_t<Tasks>...>, void>*
@@ -151,6 +175,14 @@ auto Executor::dependent_async(
151175
return std::make_pair(AsyncTask(std::move(node)), std::move(fu));
152176
}
153177

178+
// Function: dependent_async
179+
template <typename F, typename I,
180+
std::enable_if_t<!std::is_same_v<std::decay_t<I>, AsyncTask>, void>*
181+
>
182+
auto Executor::dependent_async(F&& func, I first, I last) {
183+
return dependent_async("", std::forward<F>(func), first, last);
184+
}
185+
154186
// Function: dependent_async
155187
template <typename F, typename I,
156188
std::enable_if_t<!std::is_same_v<std::decay_t<I>, AsyncTask>, void>*

taskflow/core/executor.hpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,10 @@ class Executor {
654654
*/
655655
template <typename F>
656656
void silent_async(const std::string& name, F&& f);
657+
658+
// --------------------------------------------------------------------------
659+
// Observer methods
660+
// --------------------------------------------------------------------------
657661

658662
/**
659663
@brief constructs an observer to inspect the activities of worker threads
@@ -689,9 +693,17 @@ class Executor {
689693
size_t num_observers() const noexcept;
690694

691695
// --------------------------------------------------------------------------
692-
// asynchronous tasking with dependents
696+
// Silent Dependent Async Methods
693697
// --------------------------------------------------------------------------
694698

699+
/**
700+
@brief TODO
701+
*/
702+
template <typename F, typename... Tasks,
703+
std::enable_if_t<all_same_v<AsyncTask, std::decay_t<Tasks>...>, void>* = nullptr
704+
>
705+
tf::AsyncTask silent_dependent_async(F&& func, Tasks&&... tasks);
706+
695707
/**
696708
@brief TODO
697709
*/
@@ -700,6 +712,14 @@ class Executor {
700712
>
701713
tf::AsyncTask silent_dependent_async(const std::string& name, F&& func, Tasks&&... tasks);
702714

715+
/**
716+
@brief TODO
717+
*/
718+
template <typename F, typename I,
719+
std::enable_if_t<!std::is_same_v<std::decay_t<I>, AsyncTask>, void>* = nullptr
720+
>
721+
tf::AsyncTask silent_dependent_async(F&& func, I first, I last);
722+
703723
/**
704724
@brief TODO
705725
*/
@@ -708,6 +728,18 @@ class Executor {
708728
>
709729
tf::AsyncTask silent_dependent_async(const std::string& name, F&& func, I first, I last);
710730

731+
// --------------------------------------------------------------------------
732+
// Dependent Async Methods
733+
// --------------------------------------------------------------------------
734+
735+
/**
736+
@brief TODO
737+
*/
738+
template <typename F, typename... Tasks,
739+
std::enable_if_t<all_same_v<AsyncTask, std::decay_t<Tasks>...>, void>* = nullptr
740+
>
741+
auto dependent_async(F&& func, Tasks&&... tasks);
742+
711743
/**
712744
@brief TODO
713745
*/
@@ -716,6 +748,14 @@ class Executor {
716748
>
717749
auto dependent_async(const std::string& name, F&& func, Tasks&&... tasks);
718750

751+
/**
752+
@brief TODO
753+
*/
754+
template <typename F, typename I,
755+
std::enable_if_t<!std::is_same_v<std::decay_t<I>, AsyncTask>, void>* = nullptr
756+
>
757+
auto dependent_async(F&& func, I first, I last);
758+
719759
/**
720760
@brief TODO
721761
*/

unittests/test_dependent_asyncs.cpp

Lines changed: 189 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,6 @@ TEST_CASE("SilentDependentAsync.SimpleGraph.16threads" * doctest::timeout(300))
239239
// Simple Graph 2
240240
// ----------------------------------------------------------------------------
241241

242-
// --------------------------------------------------------------------
243-
// Graph 2
244-
// --------------------------------------------------------------------
245-
//
246242
// task dependence :
247243
// ----------------------------
248244
// | |--> 3 --| |
@@ -418,6 +414,195 @@ TEST_CASE("SilentDependentAsync.SimpleGraph2.16threads" * doctest::timeout(300))
418414
silent_dependent_async_simple_graph_2(16);
419415
}
420416

417+
// task dependence :
418+
// ----------------------------
419+
// | |--> 3 --| |
420+
// | | --> 7 --->|
421+
// 0 ---| |--> 4 --| |
422+
// v ^ v
423+
// --> 2 --| ---------------------> 9
424+
// ^ v ^
425+
// 1 ---| |--> 5 --| |
426+
// | | --> 8 --->|
427+
// | |--> 6 --| |
428+
// -----------------------------
429+
void dependent_async_simple_graph_2(unsigned W) {
430+
431+
tf::Executor executor(W);
432+
433+
size_t count = 10;
434+
std::vector<tf::CachelineAligned<int>> results(count);
435+
std::vector<tf::AsyncTask> tasks1;
436+
std::vector<tf::AsyncTask> tasks2;
437+
std::vector<tf::AsyncTask> tasks3;
438+
std::vector<tf::AsyncTask> tasks4;
439+
440+
for (int id = 0; id < 100; ++id) {
441+
442+
results.resize(count);
443+
444+
auto t0 = executor.silent_dependent_async(
445+
"t0", [&](){
446+
results[0].data = 100 + id;
447+
}
448+
);
449+
450+
auto t1 = executor.silent_dependent_async(
451+
"t1", [&](){
452+
results[1].data = 6 * id;
453+
}
454+
);
455+
456+
auto t2 = executor.silent_dependent_async(
457+
"t2", [&](){
458+
results[2].data = results[0].data + results[1].data + id;
459+
}, t0, t1
460+
);
461+
462+
tasks1.push_back(t2);
463+
464+
auto [t3, fu3] = executor.dependent_async(
465+
"t3", [&](){
466+
results[3].data = results[2].data + id;
467+
return results[3].data;
468+
}, tasks1.begin(), tasks1.end()
469+
);
470+
471+
auto t4 = executor.silent_dependent_async(
472+
"t4", [&](){
473+
results[4].data = results[2].data + id;
474+
}, tasks1.begin(), tasks1.end()
475+
);
476+
477+
auto [t5, fu5] = executor.dependent_async(
478+
"t5", [&](){
479+
results[5].data = results[2].data + id;
480+
return results[5].data;
481+
}, tasks1.begin(), tasks1.end()
482+
);
483+
484+
auto t6 = executor.silent_dependent_async(
485+
"t6", [&](){
486+
results[6].data = results[2].data + id;
487+
}, tasks1.begin(), tasks1.end()
488+
);
489+
490+
tasks2.push_back(t3);
491+
tasks2.push_back(t4);
492+
tasks3.push_back(t5);
493+
tasks3.push_back(t6);
494+
495+
auto [t7, fu7] = executor.dependent_async(
496+
"t7", [&](){
497+
results[7].data = results[3].data + results[4].data + id;
498+
return results[7].data;
499+
}, tasks2.begin(), tasks2.end()
500+
);
501+
502+
auto t8 = executor.silent_dependent_async(
503+
"t8", [&](){
504+
results[8].data = results[5].data + results[6].data + id;
505+
}, tasks3.begin(), tasks3.end()
506+
);
507+
508+
tasks4.push_back(t0);
509+
tasks4.push_back(t1);
510+
tasks4.push_back(t2);
511+
tasks4.push_back(t7);
512+
tasks4.push_back(t8);
513+
514+
auto [t9, fu9] = executor.dependent_async(
515+
"t9", [&](){
516+
results[9].data = results[0].data + results[1].data +
517+
results[2].data + results[7].data + results[8].data + id;
518+
return results[9].data;
519+
}, tasks4.begin(), tasks4.end()
520+
);
521+
522+
523+
REQUIRE(fu9.get() == results[9].data);
524+
525+
REQUIRE(fu3.wait_for(std::chrono::microseconds(1)) == std::future_status::ready);
526+
REQUIRE(fu3.get() == results[3].data);
527+
528+
REQUIRE(fu5.wait_for(std::chrono::microseconds(1)) == std::future_status::ready);
529+
REQUIRE(fu5.get() == results[5].data);
530+
531+
REQUIRE(fu7.wait_for(std::chrono::microseconds(1)) == std::future_status::ready);
532+
REQUIRE(fu7.get() == results[7].data);
533+
534+
for (size_t i = 0; i < count; ++i) {
535+
switch (i) {
536+
case 0:
537+
REQUIRE(results[i].data == 100 + id);
538+
break;
539+
540+
case 1:
541+
REQUIRE(results[i].data == 6 * id);
542+
break;
543+
544+
case 2:
545+
REQUIRE(results[i].data == results[0].data + results[1].data + id);
546+
break;
547+
548+
case 3:
549+
REQUIRE(results[i].data == results[2].data + id);
550+
break;
551+
552+
case 4:
553+
REQUIRE(results[i].data == results[2].data+ id);
554+
break;
555+
556+
case 5:
557+
REQUIRE(results[i].data == results[2].data + id);
558+
break;
559+
560+
case 6:
561+
REQUIRE(results[i].data == results[2].data + id);
562+
break;
563+
564+
case 7:
565+
REQUIRE(results[i].data == results[3].data + results[4].data + id);
566+
break;
567+
568+
case 8:
569+
REQUIRE(results[i].data == results[5].data + results[5].data + id);
570+
break;
571+
572+
case 9:
573+
REQUIRE(results[i].data == results[0].data + results[1].data +
574+
results[2].data + results[7].data + results[8].data + id);
575+
break;
576+
}
577+
}
578+
579+
results.clear();
580+
tasks1.clear();
581+
tasks2.clear();
582+
tasks3.clear();
583+
tasks4.clear();
584+
}
585+
}
586+
587+
TEST_CASE("DependentAsync.SimpleGraph2.1thread" * doctest::timeout(300)) {
588+
dependent_async_simple_graph_2(1);
589+
}
590+
591+
TEST_CASE("DependentAsync.SimpleGraph2.2threads" * doctest::timeout(300)) {
592+
dependent_async_simple_graph_2(2);
593+
}
594+
595+
TEST_CASE("DependentAsync.SimpleGraph2.4threads" * doctest::timeout(300)) {
596+
dependent_async_simple_graph_2(4);
597+
}
598+
599+
TEST_CASE("DependentAsync.SimpleGraph2.8threads" * doctest::timeout(300)) {
600+
dependent_async_simple_graph_2(8);
601+
}
602+
603+
TEST_CASE("DependentAsync.SimpleGraph2.16threads" * doctest::timeout(300)) {
604+
dependent_async_simple_graph_2(16);
605+
}
421606

422607
// ----------------------------------------------------------------------------
423608
// Binary Tree

0 commit comments

Comments
 (0)