How can I assign a name to a task in TPL

后端 未结 11 1272
礼貌的吻别
礼貌的吻别 2021-02-12 10:24

I\'m going to use lots of tasks running on my application. Each bunch of tasks is running for some reason. I would like to name these tasks so when I watch the Parallel Tasks wi

相关标签:
11条回答
  • 2021-02-12 11:28

    You could relate any object with any object. Here is an extension for Task. It uses a WeakReference so the task can still be garbage collected when all references are out of scope.

    Usage:

    var myTask = new Task(...
    myTask.Tag("The name here");
    var nameOfTask = (string)myTask.Tag();
    

    Extension class:

    public static class TaskExtensions
    {
        private static readonly Dictionary<WeakReference<Task>, object> TaskNames = new Dictionary<WeakReference<Task>, object>(); 
    
        public static void Tag(this Task pTask, object pTag)
        {
            if (pTask == null) return;
            var weakReference = ContainsTask(pTask);
            if (weakReference == null)
            {
                weakReference = new WeakReference<Task>(pTask);
            }
            TaskNames[weakReference] = pTag;
        }
    
        public static object Tag(this Task pTask)
        {
            var weakReference = ContainsTask(pTask);
            if (weakReference == null) return null;
            return TaskNames[weakReference];
        }
    
        private static WeakReference<Task> ContainsTask(Task pTask)
        {
            foreach (var kvp in TaskNames.ToList())
            {
                var weakReference = kvp.Key;
    
                Task taskFromReference;
                if (!weakReference.TryGetTarget(out taskFromReference))
                {
                    TaskNames.Remove(weakReference); //Keep the dictionary clean.
                    continue;
                }
    
                if (pTask == taskFromReference)
                {
                    return weakReference;
                }
            }
            return null;
        }
    }
    
    0 讨论(0)
  • 2021-02-12 11:28

    In case this is helpful for anyone, I addressed the above issue as follows:

    public static class NamedTasks
    {
        public static Dictionary<string, Task> ActiveTasks { get; private set; } = new Dictionary<string, Task>();
    
        public static void Run(string name, Action action)
        {
            var task = new Task(action);
            ActiveTasks.Add(name, task);
            task.Start();
    
        public static void RemoveTask(string name)
        {
            if (ActiveTasks.ContainsKey(name))
                ActiveTasks.Remove(name);
        }
    }
    

    Usage:

    // Start new named task
    var taskName = "<code file> - <method>";
    NamedTasks.Run(taskName, () =>
    {
        // do stuff
        NamedTasks.RemoveTask(taskName);
    });
    
    ...
    
    // Print names of active tasks
    var taskNames = NamedTasks.ActiveTasks.Keys.ToList();
    foreach (var taskName in taskNames)
        if (NamedTasks.ActiveTasks[taskName].Status == TaskStatus.Running)
            Console.WriteLine(taskName);
    

    This worked quite nicely for me.

    0 讨论(0)
  • 2021-02-12 11:29

    You can't name tasks.

    The task library is internally using a thread pool, so the threads can't be named. Also your inheritance approach won't work, because methods like ".ContinueWith()" will always create a new task, which won't inherit from your class.

    0 讨论(0)
  • 2021-02-12 11:29
    public class NamesTask {
        readonly Queue<Task> _taskqueue = new Queue<Task>();
        private readonly object _queueLock = new object();
    
        public Task RunTask(Action action) {
            //incoming task must be queued as soon as it arrives
            var inComingTask = new Task(action);
    
            lock (_queueLock) {
                _taskqueue.Enqueue(inComingTask);
            }
    
            return Task.Factory.StartNew(() => {
                //run all actions one by one..
                while (true) {
                    lock (_queueLock) { //only one task must be performed at a 
                        if (_taskqueue.Count == 0) return;
    
                        var outTask = _taskqueue.Dequeue();
    
                        outTask.Start();
                        outTask.Wait();
    
                        Console.WriteLine("done....");
                    }
                }
            });
        }
    }
    
    0 讨论(0)
  • 2021-02-12 11:30

    I thought of having a dictionary to aid debugging, etc.

    Here's a sample of what I have been doing:

    private static void Main(string[] args)
    {
        var tasksIdDic = new ConcurrentDictionary<int?, string>();
        Random rnd = new Random(DateTime.Now.Millisecond);
        var tasks = new List<Task>();
    
        tasks.Add(Task.Run(() =>  
        {
            Task.Delay(TimeSpan.FromSeconds(rnd.Next(1, 5))).Wait();
            tasksIdDic.TryAdd(Task.CurrentId, "First");
    
            Console.WriteLine($"{tasksIdDic[Task.CurrentId]} completed.");
        }));
    
        tasks.Add(Task.Run(() =>
        {
            Task.Delay(TimeSpan.FromSeconds(rnd.Next(1, 5))).Wait();
            tasksIdDic.TryAdd(Task.CurrentId, "Second");
    
            Console.WriteLine($"{tasksIdDic[Task.CurrentId]} completed.");
        }));
    
        tasks.Add(Task.Run(() =>
        {
            Task.Delay(TimeSpan.FromSeconds(rnd.Next(1, 5))).Wait();
            tasksIdDic.TryAdd(Task.CurrentId, "Third");
    
            Console.WriteLine($"{tasksIdDic[Task.CurrentId]} completed.");
        }));
    
       //do some work - there is no guarantee, but assuming you add the task names to the dictionary at the very beginning of each thread, the dictionary will be populated and be of benefit sometime soon after the start of the tasks.
       //Task.Delay(TimeSpan.FromSeconds(5)).Wait();
    
        //wait for all just so I see a console output
        Task.WaitAll(tasks.ToArray());
    }
    

    0 讨论(0)
提交回复
热议问题