How can I assign a name to a task in TPL

送分小仙女□ 提交于 2019-12-03 09:50:19

You can't really name a Task, but you can name the method which is executed by a Task, which is then shown in the Parallel Tasks windows. So, if naming the Tasks is important for you, don't use lambdas, use normal named methods.

Surprisingly, this works even with Parallel, even though there the Task isn't executing your method directly. I think this is because Parallel Tasks somehow knows about Tasks from Parallel and handles them differently.

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

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.

If you only need to know the name of the task after the task is finished then you could just pass it as a parameter. Return it as a part of the task result.

    private async Task<string[]> MyTask(int x, string taskName)
    {
        return new[]
        {
            taskName, x.ToString()
        };
    }

Or map your tasks to a dictionary

        var mapping = new Dictionary<Task, string>();
        var task = new Task(() => Console.WriteLine("myNullTask"));
        mapping.Add(task, "myNullTask");
        foreach (var taskX in mapping)
        {
            Console.WriteLine(
                $"Task Id: {taskX.Key.Id}, " +
                $"Task Name: {taskX.Value}, " +
                $"Task Status: {taskX.Key.Status}");
        }

I dont think you can name the tasks. You can use Task.Id to track the tasks.

I'm shooting blind here as I don't know the behavior of Parallel Tasks window but if it uses the debugger api adding a DebuggerDisplay attribute on your NamedTask subclass might help

Arvind Kumar Chaodhary
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....");
                }
            }
        });
    }
}

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

Arvind Kumar Chaodhary
public class NamedTaskSchedular
{
    private static readonly ConcurrentDictionary<string, NamesTask> NamedTaskDictionary = new ConcurrentDictionary<string, NamesTask>();

    public static Task RunNamedTask(string name, Action action)
    {
        if (NamedTaskDictionary.ContainsKey(name))
        {
            return NamedTaskDictionary[name].RunTask(action);
        }
        var task = new NamesTask();

        NamedTaskDictionary[name] = task;

        return task.RunTask(action);
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!