-->

我如何分配一个名称在TPL任务(How can I assign a name to a task

2019-08-03 15:59发布

我将使用大量上我的应用程序运行的任务。 任务中的每一束正在运行的某些原因。 我想命名这些任务,所以当我看并行任务窗口中,我可以很容易地识别它们。

随着另一种观点认为,考虑我使用任务在框架层面来填充列表。 使用我的框架,开发人员还利用她的工作任务。 如果她看起来在并行任务窗口中她会发现没有关于这一想法的任务。 我想命名的任务,让她可以从她的任务区分框架的任务。

这将是非常方便的,如果有这样的API:

var task = new Task(action, "Growth calculation task")

或者可能:

var task = Task.Factory.StartNew(action, "Populating the datagrid")

甚至在与工作Parallel.ForEach

Parallel.ForEach(list, action, "Salary Calculation Task"

是否有可能名称的任务?

是否有可能给Parallel.ForEach命名结构(也许使用Lambda),所以它与命名创建任务?

是否有这样的API的地方我失踪?


我也试图使用一个继承的任务来覆盖它的toString()。 但不幸的是并行任务窗口不使用的ToString()!

class NamedTask : Task
{
    private string TaskName { get; set; }
    public NamedTask(Action action, string taskName):base(action)
    {
        TaskName = taskName;
    }

    public override string ToString()
    {
        return TaskName;
    }
}

Answer 1:

你真的不能命名一个Task ,但你能说出它由执行方法Task ,然后在并行任务窗口中显示。 所以,如果命名Task s是对你很重要,不要使用lambda表达式,使用普通的命名方法。

出人意料的是,这个工程即使有Parallel ,即使该Task不直接执行你的方法。 我想这是因为并行任务莫名其妙地知道Task从s Parallel和不同的方式处理它们。



Answer 2:

你可能涉及与任何对象的任何对象。 这里是工作的延伸。 它采用所以当所有引用超出范围的任务仍然可以收集垃圾的WeakReference一个。

用法:

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

扩展类:

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


Answer 3:

你不能说出的任务。

任务库在内部使用线程池,所以线程不能被命名。 此外,您的继承方法是行不通的,因为类似的方法“.ContinueWith()”总是会创建一个新的任务,这将不会从你的类继承。



Answer 4:

如果你只需要知道任务的名称,完成后的任务,那么你可以只把它作为一个参数。 返回它作为任务结果的一部分。

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

或者你的任务映射到词典

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


Answer 5:

我不认为你可以命名的任务。 您可以使用Task.Id跟踪任务。



Answer 6:

我在这里拍摄的盲目不知并行任务窗口的行为,但如果它使用调试器API添加DebuggerDisplay属性您NamedTask子类可以帮助



Answer 7:

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


Answer 8:

我想有一本字典来帮助调试等。

这里是我一直在做的一个示例:

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



Answer 9:

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


文章来源: How can I assign a name to a task in TPL