{"id":56013,"date":"2012-03-04T08:24:46","date_gmt":"2012-03-04T08:24:46","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2012\/03\/04\/implementing-a-simple-foreachasync\/"},"modified":"2012-03-04T08:24:46","modified_gmt":"2012-03-04T08:24:46","slug":"implementing-a-simple-foreachasync","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/implementing-a-simple-foreachasync\/","title":{"rendered":"Implementing a simple ForEachAsync"},"content":{"rendered":"<p><a href=\"https:\/\/msmvps.com\/blogs\/jon_skeet\/\">Jon Skeet<\/a> recently asked me how I might go about implementing the following &ldquo;asynchronous ForEach&rdquo; behavior:<\/p>\n<ul>\n<li>For each element in an enumerable, run a function that returns a Task&lt;TResult&gt; to represent the completion of processing that element. All of these functions may run asynchronously concurrently. <\/li>\n<li>As each task completes, run a second processing action over the results.&nbsp; All of these actions must be run sequentially, but order doesn&rsquo;t matter. <\/li>\n<\/ul>\n<p>Given what we now know about SemaphoreSlim from my <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/02\/29\/10274035.aspx\">previous post<\/a>, here&rsquo;s one way to achieve this:<\/p>\n<blockquote>\n<p><font face=\"Consolas\"><font color=\"#0000ff\">public static<\/font> <font color=\"#4bacc6\">Task<\/font> ForEachAsync&lt;TSource, TResult&gt;(         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">this<\/font> <font color=\"#4bacc6\">IEnumerable<\/font>&lt;TSource&gt; source,         <br>&nbsp;&nbsp;&nbsp; <font color=\"#4bacc6\">Func<\/font>&lt;TSource, Task&lt;TResult&gt;&gt; taskSelector, <font color=\"#4bacc6\">Action<\/font>&lt;TSource, TResult&gt; resultProcessor)         <br><\/font><font face=\"Consolas\">{        <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">var<\/font> oneAtATime = <font color=\"#0000ff\">new<\/font> <font color=\"#4bacc6\">SemaphoreSlim<\/font>(initialCount:1, maxCount:1);         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">return <\/font><font color=\"#4bacc6\">Task<\/font>.WhenAll(         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">from<\/font> item <font color=\"#0000ff\">in<\/font> source         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">select<\/font> ProcessAsync(item, taskSelector, resultProcessor, oneAtATime));         <br>}         <\/p>\n<p><\/font><font face=\"Consolas\"><font color=\"#0000ff\">private static async<\/font> <font color=\"#4bacc6\">Task<\/font> ProcessAsync&lt;TSource, TResult&gt;(         <br>&nbsp;&nbsp;&nbsp; TSource item,         <br>&nbsp;&nbsp;&nbsp; <font color=\"#4bacc6\">Func<\/font>&lt;TSource, <font color=\"#4bacc6\">Task<\/font>&lt;TResult&gt;&gt; taskSelector, <font color=\"#4bacc6\">Action<\/font>&lt;TSource, TResult&gt; resultProcessor,         <br>&nbsp;&nbsp;&nbsp; <font color=\"#4bacc6\">SemaphoreSlim<\/font> oneAtATime)         <br>{         <br>&nbsp;&nbsp;&nbsp; TResult result = <font color=\"#0000ff\">await<\/font> taskSelector(item);         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">await<\/font> oneAtATime.WaitAsync();         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">try<\/font> { resultProcessor(item, result); }         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">finally<\/font> { oneAtATime.Release(); }         <br>}<\/font><\/p>\n<\/blockquote>\n<p>We instantiate a semaphore initialized with a count of 1, and we use this to throttle the follow-up actions to ensure that only one at a time runs.&nbsp; We then call the ProcessAsync method for each element, passing in the element, the semaphore, and the delegates to invoke.&nbsp; Inside ProcessAsync, we first run the function and await its completion.&nbsp; Once it&rsquo;s complete, we acquire the semaphore to ensure that we run the result processing function sequentially with regards to all the other processing function.<\/p>\n<p>Thanks for the question\/suggestion, Jon!<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Jon Skeet recently asked me how I might go about implementing the following &ldquo;asynchronous ForEach&rdquo; behavior: For each element in an enumerable, run a function that returns a Task&lt;TResult&gt; to represent the completion of processing that element. All of these functions may run asynchronously concurrently. As each task completes, run a second processing action over [&hellip;]<\/p>\n","protected":false},"author":360,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[7925,36,7911,7909,7912],"class_list":["post-56013","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-net-4-5","tag-async","tag-code-samples","tag-parallel-extensions","tag-task-parallel-library"],"acf":[],"blog_post_summary":"<p>Jon Skeet recently asked me how I might go about implementing the following &ldquo;asynchronous ForEach&rdquo; behavior: For each element in an enumerable, run a function that returns a Task&lt;TResult&gt; to represent the completion of processing that element. All of these functions may run asynchronously concurrently. As each task completes, run a second processing action over [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56013","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/360"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=56013"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56013\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=56013"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=56013"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=56013"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}