简体   繁体   中英

Use of Task.WhenAny with dictionary

I am currently writing a service which will create Task for each request he find as "Waiting for process" in the database.

The process can be long, and I want the service to check each time it loops if the task must be cancel, if it's the case I want to cancel the task with a token. So I need to store the ID of the request linked to the task.

I was thinking about having my static class with a dictionary as following:

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

Which I don't know if it's the better solution that exist but it still a working one I think.

Now I want to do a Task.WhenAny(..) to know when one of them is ended. The problem is that Task.WhenAny(..) accept an array, but not a Dictionary. I didn't see anything about passing a dictionary to a WhenAny and before I start working on the entire process which is very long I wanted to have a solution for each keypoint of my workflow. I could have get a list of the values of the dictionary but I would probably loose the id link. So I don't really know what to do ?

Is there a solution for that ? I don't wanted to recreate my "own" WhenAny and I don't even know if it's possible but I assume I can just parse the status of every row. However if it's the only option, I will.

I'm also open about the fact that storing the id of the request this way isn't a good way to do and in this case I'm open to any other suggestion.


EDIT : CODE ACORDING TO ANSWERS I ended using this code which seems to be working. Now I'll test with more complicated tasks rather than just a file writing ! :)

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;
    }
}

有一个Task.WhenAny具有IEnumerable<Task> ,而一个具有IEnumerable<Task<T>> ,所以您应该可以使用:

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

Task.WhenAny return value is:

A task that represents the completion of one of the supplied tasks. The return task's Result is the task that completed.

From the docs .

So basically you can pass to it the dictionary values and by awaiting it you will get the task that was finished, from here it is easy to attach to this task it's id using some LINQ:

var task = await Task.WhenAny(_tasks.Values);
var id = _tasks.Single(pair => pair.Value == task).Key;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM