C#—不能对已完成的任务执行Start
在一次项目中出现了一个报错,不能在已完成,已出错,未完成的任务Start,不知道什么原由,会出现这样的问题,但是今天又把它复现了一遍。
1、出错代码
int sum = 0;
int Init = 0;
public Task<int> ComputerTask;
public async void InitComputerTask()
{
ComputerTask = Task.Factory.StartNew(() =>
{
for (int i = Init; i < 100000; i++)
{
Thread.Sleep(800);
sum += i;
Log = $"sum={sum}";
if (Source.IsCancellationRequested)
{
Log = "计算任务还没有执行结束,计算终止";
break;
}
}
return sum;
}, Source.Token);
await Task.Delay(2000);
int Result= await ComputerTask;
Log= $"此次计算的结果为{Result}";
}
public void StopComputerTask()
{
if (!Source.IsCancellationRequested)
{
Source.Cancel();
}
}
public void RestartComputerTask()
{
if( ComputerTask!=null)
{
Init += 1;
ComputerTask.Start();
}
}
代码说明:这里我定义了一个任务ComputerTask,,初始化任务是计算从0-100000 的和。StopComputerTask方法,用CancellationTakenSoure+ CancellationTaken的方法,中途可以取消任务。RestartComputerTask 重新执行此任务。
运行程序,开始任务,结束任务没问题,重启任务结果报错:
我不知道为啥,不能对已完成的任务进行Start。
但是这里有一个解决方法,虽然任务Start之后不能Start
如果是这样的话,那岂不是我写的任务,只能执行一次,如果我想重新启动任务就启动不了了。
2、解决问题的办法
要想实现这个功能有一个解决办法,就是任务可以用委托来定义,用委托来定义指向任务的指针。若想重启任务,直接调用委托。这样任务就能再次被执行了。
//单个任务
public Func<Task> CurrtentTask;
public async Task InitTask()
{
int n = 0;
CurrtentTask = async () =>
await Task.Run(() =>
{
while (!Source.IsCancellationRequested)
{
Thread.Sleep(1000);
Log = "log" + (n++).ToString();
}
Source = new CancellationTokenSource();
}, Source.Token);
}
public void CancelTask()
{
if (!Source.IsCancellationRequested)
{
Source.Cancel();
}
}
public async Task ExecuteTask()
{
if (CurrtentTask == null)
await InitTask();
await CurrtentTask();
}
public async Task RestartTask()
{
if (CurrtentTask != null)
{
await CurrtentTask();
}
}
这里为了多练习,我这里又重新写了一个委托,这个委托是Func CurrentTask. 初始化这个委托变量,这个委托变量里面有异步任务,这里应用委托来包装异步任务,可以让异步任务 多次启动。为什么这里用Func 主要是因为 使用异步async void 不能破获到异常,所以这里用到async Task .通过这种方式可以让委托多次执行异步任务。而不会报错。
结果:按下启动按钮,异步任务执行,按下取消按钮异步任务结束、按下重启按钮异步任务又开始执行。
3、总结归纳
在实际项目开发中,如果想要多次执行异步任务,不能直接定义次异步任务,因为一旦创建并执行此异步任务,再想要重新启动,不能用Start方法,这样会报错。
采取的解决问题的方式是,使用委托包装异步任务,这样可以多次重复执行异步任务,不会报错。