threads thread tasks que net crear c# task-parallel-library parallel.foreach

tasks - task thread c#



¿Cómo puedo asignar un nombre a una tarea en TPL? (9)

Voy a usar muchas tareas que se ejecutan en mi aplicación. Cada grupo de tareas se está ejecutando por alguna razón. Me gustaría nombrar estas tareas para que cuando vea la ventana Tareas paralelas, pueda reconocerlas fácilmente.

Con otro punto de vista, considere que estoy usando tareas en el nivel de marco para completar una lista. Un desarrollador que usa mi framework también usa tareas para su trabajo. Si mira la ventana Tareas paralelas, encontrará algunas tareas que no tienen idea. Quiero nombrar tareas para que ella pueda distinguir las tareas marco de sus tareas.

Sería muy conveniente si hubiera tal API:

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

o tal vez:

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

o incluso mientras trabajas con Parallel.ForEach

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

¿Es posible nombrar una tarea?

¿Es posible dar a Parallel.ForEach una estructura de nombres (tal vez usando un lambda) para que cree tareas con ese nombre?

¿Hay tal API en algún lugar que me falta?

También he intentado usar una tarea heredada para anular su ToString (). ¡Pero desafortunadamente la ventana de tareas paralelas no usa 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; } }


Me estoy quedando a ciegas aquí porque no conozco el comportamiento de la ventana de Tareas paralelas, pero si usa la api del depurador, agregar un atributo DebuggerDisplay en su subclase NamedTask podría ayudar


No creo que puedas nombrar las tareas. Puede utilizar Task.Id para realizar un seguimiento de las tareas.


No puedes nombrar tareas.

La biblioteca de tareas está utilizando internamente un grupo de subprocesos, por lo que no se pueden nombrar los subprocesos. Además, su enfoque de herencia no funcionará, porque los métodos como ".ContinueWith ()" siempre crearán una nueva tarea, que no heredará de su clase.


Pensé en tener un diccionario para ayudar a la depuración, etc.

Aquí hay una muestra de lo que he estado haciendo:

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


Podrías relacionar cualquier objeto con cualquier objeto. Aquí hay una extensión para la tarea. Utiliza una WeakReference para que la tarea aún pueda ser recogida de basura cuando todas las referencias están fuera de alcance.

Uso:

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

Clase de extensión:

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


Realmente no puede nombrar una Task , pero puede nombrar el método que se ejecuta mediante una Task , que luego se muestra en las ventanas de tareas paralelas. Por lo tanto, si nombrar las Task es importante para usted, no use lambdas, use los métodos con nombres normales.

Sorprendentemente, esto funciona incluso en Parallel , aunque la Task no está ejecutando su método directamente. Creo que esto se debe a que las tareas paralelas de alguna manera saben acerca de las Task de Parallel y las manejan de manera diferente.


Si solo necesita saber el nombre de la tarea después de que la tarea haya finalizado, simplemente puede pasarla como parámetro. Devuélvalo como parte del resultado de la tarea.

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

O asigne sus tareas a un diccionario

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


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


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