Last active
April 6, 2018 03:16
-
-
Save clemensv/6554605 to your computer and use it in GitHub Desktop.
using Task.WhenAny to drive a pump of multiple async operations in the same context (such as an I/O pump)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Example use (from an email I sent) | |
I’m using WhenAny to either register for a callback on any of the pending operations and to use | |
the IO thread that comes up with their respective completion or to execute handling of completed | |
work on the current thread (‘borrowing’ the IO thread). | |
So if I read from a socket and from a queue, first both ops hang. Queue read completes and I get | |
called back on an IO thread which continues the await. I process that completion in the loop. | |
Meanwhile the socket read completes. That IO thread pops up and just registers the fact that it’s | |
done. | |
I get done dealing with the queue work and pop back to the top of the loop and schedule a new | |
receive on the queue. Then I land in await WhenAny, which promptly continues as the socket operation | |
sits there, completed, and I’m still on the IO thread I got from the queue. | |
I process the socket completion, pop back to the top of the loop, schedule a new socket receive | |
and run into await WhenAny, which has no compilations left and thus registers for a completion | |
callback with what’s pending and then unwinds the stack to return the borrowed IO thread to the pool. | |
*/ | |
using System; | |
using System.Threading.Tasks; | |
namespace WhenAnyPattern | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
MainAsync(args).Wait(); | |
} | |
static async Task MainAsync(string[] args) | |
{ | |
var rnd = new Random(); | |
Task op1 = null; | |
Task op2 = null; | |
Task op3 = null; | |
var doneHere = new TaskCompletionSource<bool>(); | |
Task.Delay(60000).ContinueWith(obj => doneHere.SetResult(true)); | |
do | |
{ | |
// receive from the queue | |
op1 = op1 ?? Task.Delay(rnd.Next(1000)); | |
// read from the socket | |
op2 = op2 ?? Task.Delay(rnd.Next(1000)); | |
// ping delay | |
op3 = op3 ?? Task.Delay(rnd.Next(1000)); | |
// wait for any of the four operations (including completion) to be done | |
var completedTask = await Task.WhenAny(op1, op2, op3, doneHere.Task); | |
if (completedTask == op1) | |
{ | |
try | |
{ | |
Console.WriteLine("1"); | |
} | |
finally | |
{ | |
op1 = null; | |
} | |
} | |
else if (completedTask == op2) | |
{ | |
try | |
{ | |
Console.WriteLine("2"); | |
} | |
finally | |
{ | |
op2 = null; | |
} | |
} | |
else if (completedTask == op3) | |
{ | |
try | |
{ | |
Console.WriteLine("3"); | |
} | |
finally | |
{ | |
op3 = null; | |
} | |
} | |
else | |
{ | |
// closing event was fired | |
break; | |
} | |
} | |
while (true); | |
Console.WriteLine("Done"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment