I'm writing a console application that needs to copy console input one keypress at a time to a socket (while also doing other things). In order to do that, I figure I have a couple options. In the before times, I would've spun up a thread to do the work, but for this particular implementation, I've decided to use a Task instead. This has led to some confusion on my part.
I have this simple function:
private static async Task ReadConsoleInput(Socket socket, Encoding encoding, CancellationToken cancellationToken)
{
var inputCharacter = new char[1]; // we only input one character at a time
var convertedBytes = new byte[4]; // four should be enough for anyone!
while (!cancellationToken.IsCancellationRequested) {
var readKey = Console.ReadKey(true);
inputCharacter[0] = readKey.KeyChar;
var byteCount = encoding.GetBytes(inputCharacter, convertedBytes);
await socket.SendAsync(convertedBytes.AsMemory(0, byteCount), cancellationToken);
}
}
If I start a Task for this in this way:
var consoleReadTask = Task.Factory.StartNew(
async () => await ReadConsoleInput(socket, encoding, tokenSource.Token),
tokenSource.Token,
TaskCreationOptions.None,
TaskScheduler.Default);
Everything functions correctly. This seems quite odd to me, however, because ReadConsoleInput, being async, already returns a Task. Thus, I figured it would be exactly the same to start the Task in this way:
var consoleReadTask = ReadConsoleInput(socket, encoding, tokenSource.Token);
This turned out to be incorrect, however. My program hangs (somewhere else, I haven't looked into it, because that's not the point here) before I ever read any input.
To me, it seems like these two methods are functionally similar, if not identical. The Task.Factory.StartNew implementation seems weird, because normally one wouldn't start a Task with an async lambda (right? am I crazy?), but both should function, I'd think.
Why are these two implementations different?
Console.ReadKeybefore the firstawait? That would mean the async/await state machine doesn't return aTaskuntil the firstawaitis reached? I'm not sure that's correct, because some stuff happens before it hangs...awaitof "truly synchronous" operation. Try addingawait Task.Yield()orawait Task.Delay(1)before yourwhileloop.