When I cancel my async method with the following content by calling the Cancel()
method of my CancellationTokenSource
, it will stop eventually. However since the line Console.WriteLine(await reader.ReadLineAsync());
takes quite a bit to complete, I tried to pass my CancellationToken to ReadLineAsync()
as well (expecting it to return an empty string) in order to make the method more responsive to my Cancel()
call. However I could not pass a CancellationToken
to ReadLineAsync()
.
Can I cancel a call to Console.WriteLine()
or Streamreader.ReadLineAsync()
and if so, how do I do it?
Why is ReadLineAsync()
not accepting a CancellationToken
? I thought it was good practice to give Async methods an optional CancellationToken
parameter even if the method still completes after being canceled.
StreamReader reader = new StreamReader(dataStream);
while (!reader.EndOfStream)
{
if (ct.IsCancellationRequested){
ct.ThrowIfCancellationRequested();
break;
}
else
{
Console.WriteLine(await reader.ReadLineAsync());
}
}
Update
Like stated in the comments below, the Console.WriteLine()
call alone was already taking up several seconds due to a poorly formated input string of 40.000 characters per line. Breaking this down solves my response-time issues, but I am still interested in any suggestions or workarounds on how to cancel this long-running statement if for some reason writing 40.000 characters into one line was intended (for example when dumping the whole string into a file).
I like to use an infinite delay, the code is quite clean. If
waiting
is completeWhenAny
returns and thecancellationToken
will throw. Else, the result oftask
will be returned.You can't cancel
Streamreader.ReadLineAsync()
. IMHO this is because reading a single line should be very quick. But you can easily prevent theConsole.WriteLine()
from happening by using a separate task variable.The check for
ct.IsCancellationRequested
is also redundand asct.ThrowIfCancellationRequested()
will only throw if cancellation is requested.You can't cancel the operation unless it's cancellable. You can use the
WithCancellation
extension method to have your code flow behave as if it was cancelled, but the underlying would still run:Usage:
You can't cancel
Console.WriteLine
and you don't need to. It's instantaneous if you have a reasonable sizedstring
.About the guideline: If your implementation doesn't actually support cancellation you shouldn't be accepting a token since it sends a mixed message.
If you do have a huge string to write to the console you shouldn't use
Console.WriteLine
. You can write the string in a character at a time and have that method be cancellable:An even better solution would be to write in batches instead of single characters. Here's an implementation using
MoreLinq
'sBatch
:So, in conclusion:
I generalized this answer to this:
Now you can use your cancellation token on any cancelable async method. For example WebRequest.GetResponseAsync:
will become:
See example http://pastebin.com/KauKE0rW