2012-12-07 6 views
16

私のアプリケーションでたくさんのタスクを使用します。タスクの各束は何らかの理由で実行されています。私はこれらのタスクに名前を付けたいので、Parallel Tasksウィンドウを見ると簡単に認識できました。TPLのタスクに名前を割り当てる方法

別の観点として、フレームワークレベルでタスクを使用してリストを作成しているとします。私のフレームワークを使用する開発者は、仕事にもタスクを使用しています。彼女がParallel Tasks Windowを見ると、彼女は何も知らないいくつかの仕事を見つけるだろう。私は彼女のタスクとフレームワークのタスクを区別できるようにタスクに名前を付ける。

、このような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に名前付け構造(ラムダを使用している可能性があります)を付けることができますか?

私は行方不明のAPIがありますか?


また、継承されたタスクを使用してToString()をオーバーライドしようとしました。しかし残念ながら、Parallel Tasksウィンドウは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; 
    } 
} 

答えて

4

実際にはTaskという名前は付けられませんが、Taskで実行されるメソッドの名前を指定すると、[パラレルタスク]ウィンドウに表示されます。したがって、Taskの名前が重要な場合は、lambdasを使用せず、通常の名前付きの方法を使用してください。

Taskが直接あなたのメソッドを実行していないのに、意外にも、これはParallelでさえも機能します。これはParallel Tasksが何とかTaskを知っていて、Parallelからそれらを別々に扱うからです。

+4

これはいいですが、同じメソッドを実行している複数のタスクを持っている非常に多くの場合、これはあまり役に立ちません。 –

+0

これは良い解決策であり、実用的なものです。ありがとう。しかし、名前をつくるほうがよかったです。たとえば、人Aの計算、人Bの計算、...パラメトリックな命名法は良いでしょう...しかし、私の根本的な問題は、そこにあるタスクには単純な名前プロパティがないのです。 – mehrandvd

1

タスクに名前を付けることはできません。 Task.Idを使用してタスクを追跡できます。

1

私は並列タスクウィンドウの動作を知っていないとして、ここでブラインドを撮影していますが、それはあなたのNamedTaskサブクラスにDebuggerDisplay属性を追加し、デバッガのAPIを使用する場合は、タスクに名前を付けることはできません

+0

感謝。ニースの属性。それは助けて、私はそれを確認します。しかし、問題は残っています。タスクは名前を持たないものですか?どうして? – mehrandvd

+0

属性を確認しました。 Parallel Tasksウィンドウでは使用しません。この属性を使用する代わりに、ToString()をオーバーライドできます。 – mehrandvd

2

に役立つかもしれません。

タスク・ライブラリーは内部的にスレッド・プールを使用しているため、スレッドの名前を付けることはできません。また、 ".ContinueWith()"のようなメソッドは常にあなたのクラスを継承しない新しいタスクを作成するので、あなたの継承のアプローチは動作しません。

+0

現在、私のタイプNamedTaskのタスクを続行するためにContinueWith()は必要ありません。私はちょうど私の仕事が名前を持ってほしい。私はタスクが内部的にスレッドを使用することを知っていますが、タスクの名前を付けないようにするにはどうすればよいでしょうか?それは名前を持っている論理的な仕事のようです。 – mehrandvd

+0

タスクが名前を持つことは論理的ではないためです。タスクは短い非同期操作に使用され、長い要求には使用されません。 – JustAnotherUserYouMayKnow

14

オブジェクトをオブジェクトに関連付けることができます。タスクの拡張機能を次に示します。 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; 
    } 
} 
+0

@mehrandvd私はこれが受け入れられた答えであるべきだと思います:) –

0
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

上記の2つのクラスを以下のように使います:-NamedTaskSchedular.RunNamedTask( "1"、Program.Act1); public static void Act1(){} –

-1
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

あなただけのタスクが終了した後、あなたはちょうど渡すことができるタスクの名前を知る必要がある場合それをパラメータとして使用します。それをタスク結果の一部として返します。

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}"); 
     } 
関連する問題