Soru TPL'de bir göreve nasıl isim atabilirim?


Uygulamamda çalışan birçok görev kullanacağım. Her görev grubu bir sebepten dolayı koşuyor. Bu görevleri adlandırmak isterim ki Paralel Görevler penceresini izlerken, onları kolayca tanıyabilirdim.

Başka bir bakış açısıyla, bir listeyi doldurmak için çerçeve düzeyinde görevler kullanıyorum. Çerçevemi kullanan bir geliştirici de işi için görevleri kullanıyor. Paralel Görevler Penceresine bakarsa, hakkında hiçbir fikre sahip olmayan bazı görevler görür. Görevlerin ismini vermek istiyorum, böylece görevlerini görevlerinden ayırt edebilir.

Böyle bir API olsaydı çok uygun olurdu:

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

ya da belki:

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

hatta çalışırken Parallel.ForEach

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

Bir göreve isim vermek mümkün mü?

‍‍‍ vermek mümkün müParallel.ForEach bir adlandırma yapısı (belki bir lambda kullanarak) bu adla görevler yaratır?

Eksik olduğum bir yerde böyle bir API var mı?


Ayrıca ToString () 'i geçersiz kılmak için devralınan bir görevi kullanmaya çalıştım. Ama ne yazık ki Paralel Görevler penceresi ToString () kullanmaz!

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

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

18
2017-12-07 11:34


Menşei




Cevaplar:


Gerçekten bir isim veremezsin Taskancak, tarafından yürütülen yöntemi adlandırabilirsiniz. TaskDaha sonra Paralel Görevler pencerelerinde gösterilir. Yani, eğer adlandırma Tasks sizin için önemlidir, lambda kullanmayın, normal adlandırılmış yöntemler kullanın.

Şaşırtıcı bir şekilde, bu bile ile çalışır Parallelorada olsa bile Task yönteminizi doğrudan yürütmüyor. Bunun nedeni, Paralel Görevlerin bir şekilde bilmesidir. Taskdan Parallel ve bunları farklı şekilde ele alır.


5
2017-12-09 17:00



Bu çok güzel ama çoğu zaman aynı yöntemi uygulayan birden fazla göreviniz olduğunda bu durum çok yararlı değil. - Adrian Zanescu
İyi bir çözüm ve pratik bir tanesi. Teşekkürler. Ama isimler yaratmak daha iyiydi. Örneğin, A kişisinin hesaplanması, B kişisinin hesaplanması ... Parametrik bir isimlendirme daha iyi olurdu ... Ama asıl sorum şu ki, neden buradaki görevlerde basit bir isim özelliği yok! - mehrandvd


Herhangi bir nesneyi herhangi bir nesne ile ilişkilendirebilirsiniz. İşte Görev için bir uzantısıdır. WeakReference kullanır, böylece tüm referanslar kapsam dışı olduğunda görev yine de çöp toplanabilir.

Kullanımı:

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

Uzatma sınıfı:

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

16
2017-12-22 14:54



@mehrandvd Bunun kabul edilen cevap olması gerektiğini düşünüyorum :) - Mike de Klerk


Görevleri adlandıramazsın.

Görev kitaplığı dahili olarak bir iş parçacığı havuzu kullanıyor, böylece iş parçacığı adlandırılamıyor. Ayrıca, kalıtım yaklaşımınız işe yaramaz, çünkü ".ContinueWith ()" gibi yöntemler her zaman sınıfınızdan devralmayacak yeni bir görev oluşturacaktır.


2
2017-12-07 13:36



Şu anda benim tür NamedTask bir görevine devam etmek için ContinueWith () gerek yok. Sadece görevimin bir ismine sahip olmasını istiyorum. Görevlerin konuları içsel olarak kullandığını biliyorum, ama bize bir görev vermememiz gereken nedir? Bir ismin olması mantıklı görevler gibi görünüyor. - mehrandvd
Çünkü görevlerin bir adı olması mantıklı değil. Görevler, uzun istekler için değil, kısa asenkron işlemleri için kullanılır. - JustAnotherUserYouMayKnow


Görevleri adlandırabileceğini sanmıyorum. Kullanabilirsiniz Task.Id görevleri takip etmek.


1
2017-12-07 11:40





Paralel Görevler penceresinin davranışını bilmediğim için burada kör bahis yapıyorum. DebuggerDisplay NamedTask alt sınıfınızdaki özellik yardımcı olabilir


1
2017-12-07 12:57



Teşekkürler. Güzel öznitelik. Yardımcı olabilir, kontrol edeceğim. Ama soru hala var. Görevleri olmayan bir şey var mı? niye ya? - mehrandvd
Özniteliği kontrol ettim. Paralel Görevler penceresi onu kullanmaz. Ayrıca, bu özelliği kullanmak yerine ToString () öğesini geçersiz kılabiliriz. - mehrandvd


Görev bittikten sonra yalnızca görev adını bilmeniz gerekiyorsa, bunu bir parametre olarak geçirebilirsiniz. Görev sonucunun bir parçası olarak geri verin.

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

Veya görevlerinizi bir sözlükle eşleştirin

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

1
2018-05-14 07:47





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
2018-04-21 11:37



Yukarıdaki iki sınıfı aşağıdaki gibi kullanın: -NamedTaskSchedular.RunNamedTask ("1", Program.Act1); kamusal statik boşluk Act1 () {} - Arvind Kumar Chaodhary


Hata ayıklamaya yardımcı olacak bir sözlük sahibi olmayı düşündüm.

İşte yaptığım şeyin bir örneği:

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

enter image description here


0
2017-07-25 08:02





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

-1
2018-04-21 11:39