【问题标题】:C# fetching async tasksC# 获取异步任务
【发布时间】:2016-10-28 20:15:43
【问题描述】:

一旦退出最初启动任务的方法,有没有办法通过 ID 获取当前正在运行的任务?我想以某种方式获取当前任务,这样我就可以在执行过程中停止其中一些任务,而不会中断程序的流程。

例如:

class Test
{
    List<Task> listOfTasks = new List<Task>();


    void taskCaller()
    {
        try
        {
            var myTask = Task.Factory.StartNew(()=> testMethod());
            listOfTasks.Add(myTask);
        }
        catch (System.Exception)
        {
            //...
            throw;
        }
    }


    void taskGetter()
    {
        foreach (var item in listOfTasks)
        {
            if(item == something)
            {
                item.KillExecution();
            }
        }
    }


    private void testMethod()
    {
        // doing something
        throw new NotImplementedException();
    }
}

编辑

如果可能的话,我希望它在没有取消令牌的情况下完成,因为它不适合我,因为我正在运行一个从数据库获取 DLL 的计时器,并且取消令牌只有在我立即使用 token.Cancel() 终止任务时才有效但是,如果我尝试token.CancelAfter() 它不起作用,因为它仅在任务完成执行后才会触发,这不是想法。

EDIT2:

不要复制大量代码,这是整个流程的伪代码:

new timer(repeat method every xx time units)
    open DB
    do some work
    save DB

继续plast1k 建议...

如果在这种情况下请求取消,当我检查字典时,它会显示 true,但它对正在运行的任务没有任何作用

private void getActiveTasks()
{
    if (!ListOfTasks.Any())
        return;
    Console.WriteLine("Currently running:");
    foreach (var task in ListOfTasks)
    {
        Console.WriteLine("\t" + task.Key);
        Console.WriteLine("\t" + task.Value.MyTask.Id);
        task.Value.Token.Cancel();
        Console.WriteLine("\t" + task.Value.Token.IsCancellationRequested);


        ListOfTasks.Remove(task.Key);
        return;
    }
}

【问题讨论】:

  • 不要试图成为一个混蛋,但如果取消令牌不起作用,那么你做错了什么。也许您可以解释为什么它们不起作用?见the XY problem
  • 这里,我已经更新了
  • 听起来您仍然错误地实现了取消令牌。这是一个合作的努力,从数据库中获取的方法应该定期检查传入的令牌是否已被取消,如果它有,该方法应该正常退出。不确定为什么要使用 CancelAfter 而不是 Cancel,尤其是在您想尽快取消的情况下?
  • 我不...我希望它在超时后终止
  • 没有区别,当您要求取消方法时,它要么已经从数据库中获取,要么不是,如果您在此之前和之后检查取消令牌,它仍然会正常退出.如果您要求强制轰炸该方法,那么这是一个坏主意,令牌以这种方式实现是有原因的。

标签: c# asynchronous task


【解决方案1】:

正如您可能已经研究过的那样,到目前为止,取消任务的唯一方法是使用取消令牌让它知道取消并使其知道取消。此外,这也是执行此操作的首选方法。但是,由于您的问题提到您不能使用取消源,您可以使用另一个 SO 答案中提到的技术(包括链接)。

链接中的要点,您可以创建这些任务并在不同的线程上运行它们,并在您可能想要取消任务时中止线程

How do I force a Task to stop?

【讨论】:

    【解决方案2】:

    确保您实际上是在任务内部处理取消(通过 cancelToken.ThrowIfCancellationRequested() ),因为在令牌源上调用 Cancel 只会取消任务调度,它实际上并没有停止执行。 p>

    停止任务的正确方法是使用取消标记。 在此处查看示例

    https://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx

    这里

    https://blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/recommended-patterns-for-cancellationtoken/

    【讨论】:

    • 根据他的问题,他尝试运行的方法似乎不支持取消令牌,因此即使包装器方法这样做他也无法取消外部调用。
    【解决方案3】:

    虽然您应该看到 usaipavan 的答案和链接以了解正确的取消技术,但为了跟踪您的线程或任务,您只需将它们添加到字典而不是列表并分配您选择的 ID。它可以是一个整数或一个字符串或任何东西,在这个例子中它是一个 GUID。

    Dictionary<Guid, Task> listofTasks = new Dictionary<Guid, Task>();
    
    public Guid StartTask()
    {
        Task myTask = Task.Factory.StartNew(()=> testMethod());
        Guid taskID = Guid.NewGuid();
        listOfTasks.Add(taskID, myTask);
        return taskID;
    }
    
    public void CancelTask(Guid id)
    {
        // listOfTasks[id].choose_your_own_task_cancellation_adventure()
    }
    

    如果您可以使用取消标记,您可以将它们存储在字典/另一个字典/作为元组中。如果您想识别这些任务的组(即,取消对“数据库查询”操作的所有请求),您可以执行以下操作

    public class TaskWrapper
    {
        public TaskWrapper(string operationID, Task task, CancellationTokenSource cancellationSource)
        {
            this.OperationID = operationID;
            this.Task = task;
            this.CancellationSource = cancellationSource;
        }
        public string OperationID { get; set; }
        public Task Task { get; set; }
        public CancellationTokenSource CancellationSource { get; set; }
    }
    
    
    private Dictionary<Guid, TaskWrapper> ListOfTasks = new Dictionary<Guid, TaskWrapper>();
    
    
    // populate the list
    
    
    public void CancelAll(string operation)
    {
        listOfTasks.Where(a => a.OperationID == operation).CancellationSource.Cancel();
    }
    

    【讨论】:

    • 想法很棒,但我似乎无法让令牌工作......因为我正在使用计时器(查看编辑),与特定任务相关的令牌是否可能是不知何故“被覆盖”并且不再与之相关,所以如果我取消它......什么都没有发生?
    • MyTask[id].Token.Cancel() 这样的可能吗?所以我直接知道令牌被转发到哪个任务?
    • @Norgul 是的,这是可能的 - 有关字典的更多信息,请参阅 msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx。另外,您可能无法使用取消令牌正确取消您提供的方案。
    • 我知道如何使用字典...你知道如何通过 id 或其他标识符获取任务的链接吗?还是直接访问其CancellationRequested 属性?
    猜你喜欢
    • 1970-01-01
    • 2016-05-08
    • 1970-01-01
    • 2015-12-04
    • 1970-01-01
    • 2017-09-30
    • 2013-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多