使用Task.WhenAny和字典

问题描述 投票:1回答:2

我目前正在编写一个服务,它将为数据库中的“等待进程”的每个请求创建任务。

这个过程可能很长,如果必须取消任务,我希望每次循环检查服务,如果是这种情况我想用令牌取消任务。所以我需要存储链接到任务的请求的ID。

我正在考虑将我的静态类与字典一起使用如下:

public static Dictionary<Int32, Task<Int32>> _tasks = new Dictionary<int, Task<int>>();

我不知道它是否是更好的解决方案,但我认为它仍然是一个有效的解决方案。

现在我想做一个Task.WhenAny(..)来知道其中一个什么时候结束了。问题是Task.WhenAny(..)接受一个数组,但不接受一个Dictionary。我没有看到任何关于将字典传递给WhenAny的事情,在我开始处理整个过程之前很长时间我想为我的工作流程的每个关键点找到一个解决方案。我可以得到一个字典值的列表,但我可能会松开id链接。所以我真的不知道该怎么办?

有解决方案吗?我不想重新创建我的“自己的”WhenAny,我甚至不知道它是否可能,但我想我可以解析每一行的状态。但是,如果这是唯一的选择,我会的。

我也很开放,以这种方式存储请求的id不是一个好方法,在这种情况下,我可以接受任何其他建议。


编辑:代码转到答案我结束使用这个似乎工作的代码。现在我将测试更复杂的任务,而不仅仅是文件编写! :)

public static class Worker
{
    public static List<Task<Int32>> m_tasks = new List<Task<Int32>>();
    public static Dictionary<Int32, CancellationTokenSource> m_cancellationTokenSources = new Dictionary<int, CancellationTokenSource>();
    public static Int32 _testId = 1;
    public static void run()
    {
        //Clean
        Cleaner.CleanUploads();
        Cleaner.CleanDownloads();
        #region thread watching
        if (m_tasks.Count > 0)
        {
            #region thread must be cancel
            //Cancel thread
            List<Task<Int32>> _removeTemp = new List<Task<Int32>>();
            foreach (Task<Int32> _task in m_tasks)
            {
                if (DbWorker.mustBeCancel((Int32)_task.AsyncState))
                {
                    m_cancellationTokenSources[(Int32)_task.AsyncState].Cancel();
                    //Cancellation actions

                    //task must be remove
                    _removeTemp.Add(_task);
                }
            }
            foreach( Task<Int32> _taskToRemove in _removeTemp)
            {
                m_tasks.Remove(_taskToRemove);
            }
            #endregion
            #region Conversion lookup
            // Get conversion if any

            // Create task
            CancellationTokenSource _srcCancel = new CancellationTokenSource();
            m_cancellationTokenSources.Add(_testId, _srcCancel);
            m_tasks.Add(Task.Factory.StartNew(_testId => testRunner<Int32>((Int32)_testId), _testId, _srcCancel.Token));
            _testId++;

            // Attach task
            #endregion
        }
        #endregion
        else
        {
            CancellationTokenSource _srcCancel = new CancellationTokenSource();
            m_cancellationTokenSources.Add(_testId, _srcCancel);
            m_tasks.Add(Task.Factory.StartNew(_testId => testRunner<Int32>((Int32)_testId), _testId, _srcCancel.Token));
            _testId++;
        }


    }

    internal static void WaitAll()
    {
        Task.WaitAll(m_tasks.ToArray());
    }

    public static Int32 testRunner<T>(T _id)
    {
        for (Int32 i = 0; i <= 1000000; i++)
        {
            File.AppendAllText(@"C:\TestTemp\" + _id, i.ToString());
        }
        return 2;
    }
}
c# dictionary task
2个回答
1
投票

有一个Task.WhenAny that takes an IEnumerable<Task>one that takes IEnumerable<Task<T>>,所以你应该只能使用:

var winner = Task.WhenAny(theDictionary.Values);

1
投票

Task.WhenAny返回值是:

表示已完成其中一个提供的任务的任务。返回任务的结果是完成的任务。

来自docs

所以基本上你可以传递字典值,等待它你将得到完成的任务,从这里很容易附加到这个任务它是使用一些LINQ的id:

var task = await Task.WhenAny(_tasks.Values);
var id = _tasks.Single(pair => pair.Value == task).Key;
© www.soinside.com 2019 - 2024. All rights reserved.