c#基于task能否取消长时间运行的任务?

在我的主程序中,需要处理一个不确定费时多久的工作(有可能1ms完成,也有可能50s,但是是一段顺序执行的代码,只跑一轮,没有循环),我希望当这个工作执行超过一定时间(例如3s)之后,就被停止。
我把这个工作放到business类的Hardwork()方法中去做,并被主程序调用。


        static void Main(string[] args)
        {
            business.Hardwork();
            // 预期效果是,Hardwork执行完毕后,如果在3s内完成,退回主程序,如果3s没有完成,在3s时强制退出
            Console.WriteLine("\nBACK TO THE MAIN PROCESS!");
            Console.ReadLine();
        }

 

上面代码执行后,结果如下,绿色注释部分是我的备注,也是困惑的地方:


hard working
0bok: False
1bok: False
... ...
... ...
28bok: False
29bok: False
30bok: False
System.Threading.Tasks.TaskCanceledException: 已取消一个任务。//3ms的时候收到取消的信号,并抛出了异常
hardtask:Canceled  //这里也说明hardtask任务已经取消了
bokk:False

BACK TO THE MAIN PROCESS! //这里说明已经返回了主程序,似乎一切挺好的
  //然而又过了几秒,突然一切都不好了,business.Hardwork里面的那个费时的task在Hardwork方法已经结束的情况下,竟然没有杀死,此时又返回值了,而我是想让他死的啊。。。。
hard work finished 
hw bok:True
按照上面的结果看,方法即使退出了,里面的未完成task并没有被立即杀死啊。而在这个费时task不具备被轮询的条件下,应该怎么样我才能够达到我预期的效果呢?

根据返回的index确认是哪个task执行完了,如果不是你的task,则设置CancellationToken

EndInvoke(BeginInvoke(Func<> xxx))
或者用coroutine 协程来优化你的程序。很好用

你是Task里面再执行Task,外部的Task被关掉了,里面的Task又没CancellationToken,你为啥里面还要用Task呢?

这个CancellationToken得有循环检查的才行啊
现在是我的核心业务可能会直接执行 5s,例如Thread.Sleep(5000),这个时候他并不会去检查cancellationToken的状态啊
我WaitAny,的话,如果如您所说发送cancellationtoken,我的核心业务task也一样收不到呢。。。

4.5其实和Thread.Task.StartNew()没啥太大不同的。。。

实际业务这么跑是有点多此一举,这里我主要是想验证 我外面TASK结束后,里面的那个task有没有影响,现在看是没有任何影响的。

而且里面想加CancellationToken也不难啊。。。里面的Task跑的是核心业务,例如 Thread.Sleep(5000),由于没有 while,没办法循环对 CancellationToken的是否取消做周期性轮询,所以我就没有加。因为之前试过,没有用。

现在我希望的是,对于一个内部没有循环的可能超时的task,当他超时的时候,直接把他杀死,研究了几天,还没有找到办法。
所以请您帮着想想办法。

Task本身是不支持取消的,如果取消会造成内存溢出等意外情况发生,所以不建议取消的,如果你确实业务必须要在执行过程中取消任务的话可以尝试用Thread

threadpool呢?
有没有此类功能。。。
这么看来这个task对我来说还鸡肋了。。。
Task本身是不支持取消的,如果取消会造成内存溢出等意外情况发生,所以不建议取消的,如果你确实业务必须要在执行过程中取消任务的话可以尝试用Thread

可以用一个集合:比如List

因为你虽然提出线程停止,但是因为线程还在执行过程中,所以只能是等线程执行完成后,才会停止,这个地方最好的办法是判断一下线程是否结束,没有结束等待一下,等待结束后在往下进行,线程最好不要强制终止,让他自然完成操作,不然论坛发帖机会引起其他的一系列问题。

这一系列问题包括啥呢?
task应该是属于clr的吧?这样的话垃圾收集什么的会不会好一些?

一.资源释放问题,有资源占用空间,用垃圾收集是释放不了的
二.线程相关周边的操作的完整性,因为你的线程是非正常关闭,那么和这个线程相关了的操作是否受到影响。
三.线程动作完整性,某些操作做了一半没有完成就终止了,反映出来的一些相关信息,正确性没法保证。

用 task 执行耗时的操作,是需要使用task 的返回值嘛?如果不用,换成Thread 呢?

稍加调整,在 C#4.0 中没有任何问题
Task.Factory.StartNew(
换成
Task.Factory.StartNew(

cts.CancelAfter(3000);
换成
Task.Factory.StartNew(() =>
{
   Thread.Sleep(3000);
   cts.Cancel();
});

timer是专门解决你的问题的,给你样例


private System.Threading.Timer t;

private void cancelJob(object obj)
{
    Thread tempT = (Thread)obj;
    if(tempT.IsAlive)
    {
        if (listBox1.InvokeRequired)
        {
            listBox1.Invoke(new Action(() => listBox1.Items.Add("作业将被取消...")));
        }
        t.Dispose();

        //做好强行中断线程前的准备工作,如回滚业务逻辑等
        tempT.Abort();

    }
}

private void bigJob()
{
    if(listBox1.InvokeRequired)
    {
        listBox1.Invoke(new Action(() => listBox1.Items.Add("开始处理大型作业...")));
    }
    
    Thread.Sleep(5000); //模拟耗时操作
}

private void button1_Click(object sender, EventArgs e)
{
    Thread asyncJob = new Thread(bigJob);
    asyncJob.Start();

    TimerCallback tCallBack = new TimerCallback(cancelJob);
    t = new System.Threading.Timer(tCallBack, asyncJob, 3000, 0); //3秒后启动回调函数tCallBack

    listBox1.Items.Add("主线程处理其他业务中...");

}

两者的区别在于 https://blogs.msdn.microsoft.com/pfxteam/2011/10/24/task-run-vs-task-factory-startnew/
英文的慢慢消化吧
我的理解就是:task.run 中默认不能再启动一个 task 任务,而 task.factory.startnew 可以
至于换了 CancelAfter,是因为4.0没有这个方法。不是问题的原因(我只有4.0环境)
由于你违规在前,所以出现不可预知的问题是在所必然的。

 

你可能感兴趣的:(c#基于task能否取消长时间运行的任务?)