2017-09-13 11 views
0

私はいくつかの文書を含んでいるリストを持っています。今、リストにはゆっくりとデータが取り込まれています。私がしたいのは、リストのサイズが20に達したときです。メインメソッドを停止することなく、これらの文字列を非同期的に出力する別の関数を呼び出したいとします。検索多くの後、私はこれは私が、私はなぜ唯一の最後のデータ、すなわち渡され、印刷されて把握することはできません異なるデータで同じ非同期タスクを複数呼び出すC#

List contents when calling: 0 
List contents when calling: 20 
List contents when calling: 40 
List contents when calling: 60 
1 80 
3 80 
0 80 
2 80 
4 80 
80 80 80 80 81 82 83 84 85 86 87 88 89 
81 82 83 84 85 86 87 88 89 
81 82 83 84 85 86 87 88 89 
81 82 83 84 85 86 87 88 89 
80 81 82 83 84 85 86 87 88 89 
Done DoStuff 
Done Main 

出力として取得していますものです

public void DoStuff() 
{ 
    Class1 p = new Class1(); 
    List<string> list = new List<string> { }; 
    var TList = new List<Task>(); 
    int i = 0; 
    while (i < 90) 
    { 
     list.Add(i.ToString()); 
     if (list.Count == 20) 
     { 
      Console.WriteLine("List contents when calling: " + list[0]); 
      TList.Add(Task.Run(() => publishDoc(list))); 
      list.Clear(); 
     } 
     i++; 
    } 
    if (list.Count != 0) 
    { 
     TList.Add(Task.Run(() => publishDoc(list))); 
    } 
    Task.WhenAll(TList).Wait(); 
    Console.WriteLine("Done DoStuff"); 
} 

public async Task publishDoc(List<string> docs) 
{ 
    Console.WriteLine(iter++ + " " + docs[0]); 
    await Task.Run(() => Thread.Sleep(1000)); 
    foreach (var val in docs) 
    { 
     Console.Write(val + " "); 
    } 
    Console.WriteLine(); 
} 

このコードを一緒に入れて管理しています渡されたリストが上書きされる理由私はこの

public void DoStuff() 
{ 
    Program2 p = new Program2(); 
    List<string> list = new List<string> { }; 
    int i = 0; 
    while (i < 90) 
    { 
     list.Add(i.ToString()); 
     if (list.Count == 20) 
     { 
      Console.WriteLine("List contents when calling: " + list[0]); 
      var tasks = publishDoc(list); 
      if (tasks.Result == "Done") 
      { 
       Console.WriteLine("Done " + list[0]); 
      } 
      list.Clear(); 
     } 
     i++; 
    } 
    if (list.Count != 0) 
    { 
     var tasks = publishDoc(list); 
     if (tasks.Result == "Done") 
     { 
      Console.WriteLine("Done " + list[0]); 
     } 
    } 
    Console.WriteLine("Done DoStuff"); 
} 

public async Task<string> publishDoc(List<string> docs) 
{ 
    Console.WriteLine(iter++ + " " + docs[0]); 
    foreach (var val in docs) 
    { 
     Console.Write(val + " "); 
    } 
    Console.WriteLine(); 
    return await Task.Run(() => "Done"); 
} 

をすれば は、今私は、この出力

List contents when calling: 0 
0 0 
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
Done 0 
List contents when calling: 20 
1 20 
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 
Done 20 
List contents when calling: 40 
2 40 
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 
Done 40 
List contents when calling: 60 
3 60 
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 
Done 60 
4 80 
80 81 82 83 84 85 86 87 88 89 
Done 80 
Done DoStuff 
Done Main 

これは正しい出力を与えているが、私はしたくないどの同期それをやっている取得します。助けてくれてありがとう。

+0

1. 2番目のアプローチを忘れてしまいます。 2. 'list.Clear();' - これは何をすると思いますか?タスクの参照を渡したリストをクリアします。 – Fildor

+1

あなたの最初のリスティングはほぼ正しいですが、同じリストインスタンスへの参照を渡していました。 'list.Clear();の代わりに' list = new List (); ' –

+0

を使用するこれはC#でスレッドを使うことでよくある問題です。あなたのメインタスクがwhileメソッドを通って歩いていると仮定しましょう.Task.Run()のラムダは80を取得します。<。スレッドを使用する場合は、変数を直ちに取得するParameterizedThreadStartを使用できます。残念ながら私はどのようにタスクでその問題を解決するか分かりません。 – Noren

答えて

0

あなたはループの中で、それが問題の原因かもしれません毎回リストの同じインスタンスを指すように、このようにしなければならないので、私は

while (i < 90) 
    { 
     list.Add(i.ToString()); 
     if (list.Count == 20) 
     { 
      List<string> copy = list.ToList(); 
      Console.WriteLine("List contents when calling: " + copy[0]); 
      TList.Add(Task.Run(() => publishDoc(copy))); 
      list.Clear(); 
     } 
     i++; 
    } 

を参照してくださいpublishDocに機能するためにそれを渡す前に、あなたがリストのコピーを作成することをおすすめこの回答もあります:Starting Tasks In foreach Loop Uses Value of Last Item

関連する問題