问题
As you can see in this code:
public async void TaskDelayTest()
{
while (LoopCheck)
{
for (int i = 0; i < 100; i++)
{
textBox1.Text = i.ToString();
await Task.Delay(1000);
}
}
}
I want it to set textbox to string value of i
with one second period until I set LoopCheck
value to false
. But what it does is that it creates all iteration ones in for all and even if I set LoopCheck value to false it still does what it does asyncronously.
I want to cancel all awaited Task.Delay()
iteration when I set LoopCheck=false
. How can I cancel it?
回答1:
Use the overload of Task.Delay
which accepts a CancellationToken
public async void TaskDelayTest(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
for (int i = 0; i < 100; i++)
{
textBox1.Text = i.ToString();
await Task.Delay(1000, token);
}
}
}
var tokenSource = new CancellationTokenSource();
TaskDelayTest(tokenSource.Token);
...
tokenSource.Cancel();
回答2:
If you're going to poll, poll on a CancellationToken
:
public async Task TaskDelayTestAsync(CancellationToken token)
{
for (int i = 0; i < 100; i++)
{
textBox1.Text = i.ToString();
await Task.Delay(TimeSpan.FromSeconds(1), token);
}
}
For more information, see the cancellation documentation.
回答3:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static DateTime start;
static CancellationTokenSource tokenSource;
static void Main(string[] args)
{
start = DateTime.Now;
Console.WriteLine(start);
TaskDelayTest();
TaskCancel();
Console.ReadKey();
}
public static async void TaskCancel()
{
await Task.Delay(3000);
tokenSource?.Cancel();
DateTime end = DateTime.Now;
Console.WriteLine(end);
Console.WriteLine((end - start).TotalMilliseconds);
}
public static async void TaskDelayTest()
{
tokenSource = new CancellationTokenSource();
try
{
await Task.Delay(2000, tokenSource.Token);
DateTime end = DateTime.Now;
Console.WriteLine(end);
Console.WriteLine((end - start).TotalMilliseconds);
}
catch (TaskCanceledException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
tokenSource.Dispose();
tokenSource = null;
}
}
}
}
回答4:
This might be a very stupid and elementary solution, but my idea is...
public async void TaskDelayTest()
{
while (LoopCheck)
{
for (int i = 0; i < 100; i++)
{
textBox1.Text = i.ToString();
await Delay(1000);
}
}
}
private async void Delay(int delayInMillisecond)
{
for(int i=0; i<delayInMillisecond; i++)
{
await Task.Delay(1)
if(!LoopCheck)
break;
}
}
The advantage of this approach is you only have to set LoopCheck
to false
to achieve your goal while other approaches require to use CancellationTokenSource.Cancel()
at the same time. Yes, this does take 1 millisecond at most to get out of the loop but nobody can notice that.
If you want your delay to be more accurate, try the following method.
public async void TaskDelayTest()
{
while (LoopCheck)
{
for (int i = 0; i < 100; i++)
{
textBox1.Text = i.ToString();
await Task.Run(()=>Delay(1000));
}
}
}
private void Delay(int delayInMillisecond)
{
double delayInSec = (double) delayInMillisecond / 1000;
var sw = new Stopwatch();
sw.Start();
while(true){
double ticks = sw.ElapsedTicks;
double seconds = ticks / Stopwatch.Frequency;
if(seconds >= delayInSec || !LoopCheck)
break;
}
}
来源:https://stackoverflow.com/questions/22872589/how-to-cancel-await-task-delay