2016-03-30 8 views
3

私は最高の解決策を見つけるためにあなたの助けが必要です。これは私の元のコードです:いつ多くの仕事に全部

ファイルを行で読み込み、各行をタスクで処理します。しかし、ファイルの行数が100万行以上の場合、タスクの配列は大きくなりますが、このコードはまだ有効ですか?別の解決策を見つけるべきです。私を助けてください。ありがとう。

+4

[CodeReview](http://codereview.stackexchange.com)に属しているため、このトピックを議論の対象外としています。 –

+0

TPLは内部でスレッドプールを使用しているため、100万スレッドを開始しません。タスクのパフォーマンスがどのように動作するかは不明です。 8つのコア(コアの数)を起動し、それらの8つのタスクの間で線を分割すると、パフォーマンスが向上する可能性があります。 – Domysee

+0

@YuvalItzchakovコードレビューではありません。問題を理解するコードを与えることは、多くの単語を書くことよりも優れています。私が必要とするのは、私の問題を解決するためのあなたの助けです。ありがとう。 –

答えて

4

これは悪い考えです。それはあまりにも多くのスレッドを起動する可能性があります。これを行うには

Aはるかに優れた方法は、単にそのようParallel.ForEach()を使用することです。しかしこれは、非同期/のawait使用していません

using System; 
using System.IO; 
using System.Threading.Tasks; 

namespace Demo 
{ 
    static class Program 
    { 
     static void Main() 
     { 
      string filename = @"Your test filename goes here"; 
      Parallel.ForEach(File.ReadLines(filename), process); 
     } 

     private static void process(string line) 
     { 
      Console.WriteLine(line); 
     } 
    } 
} 

。しかし、あなたが望むなら、あなたは仕事の中でParallel.ForEach()への全体の呼び出しを包むことができます。

using System; 
using System.IO; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Threading.Tasks.Dataflow; 

namespace Demo 
{ 
    static class Program 
    { 
     static void Main() 
     { 
      Task.Run(test).Wait(); 
     } 

     static async Task test() 
     { 
      string filename = @"Your filename goes here"; 
      await processFile(filename); 
     } 

     static async Task processFile(string filename) 
     { 
      var options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 8, BoundedCapacity = 100 }; 
      var action = new ActionBlock<string>(s => process(s), options); 

      foreach (var line in File.ReadLines(filename)) 
       await action.SendAsync(line); 

      action.Complete(); 

      await action.Completion; 
     } 

     static void process(string line) 
     { 
      Thread.Sleep(100); // Simulate work. 
      Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " " + line); 
     } 
    } 
} 

これはあなたにasyncサポートを提供します:あなたはTask Parallel Library(マイクロソフトNuGetパッケージ)を使用したい場合は

また、あなたはこのような何かを行うことができます。


補遺:スレッドプールの調整のデモ。

(これはシェイに応答する__さんのコメント。)

タスクがそう秒またはよりも実行に時間がかかり、長時間実行タスクの多くを開始した場合は、スロットリングのThreadPool表示される場合があります。

これは、現在のプロセスのスレッドプールスレッドの数が、ThreadPool.GetMinThreads(out workers, out ports);への呼び出しによって返されたworkerの数に等しいかそれを超える場合に発生します。

この場合、新しいスレッドプールスレッドの起動は、新しいスレッドプールスレッドが作成されるまで少し時間がかかります(システムで1秒遅れます)。多くの場合、別のスレッドプールスレッドを使用できるようになり、そのスレッドプールが代わりに使用されます(もちろん、スロットルの制限は です)。

次のコードは、問題を示しています。最初の8つのスレッドは非常に迅速に開始するが、その後、新しいスレッドが絞られているか

Min workers = 8 
Thread 3 started at time 00:00:00.0098651 
Thread 6 started at time 00:00:00.0098651 
Thread 8 started at time 00:00:00.0099841 
Thread 5 started at time 00:00:00.0099680 
Thread 7 started at time 00:00:00.0099918 
Thread 4 started at time 00:00:00.0098739 
Thread 10 started at time 00:00:00.0100828 
Thread 9 started at time 00:00:00.0101833 
Thread 11 started at time 00:00:01.0096247 
Thread 12 started at time 00:00:02.0098105 
Thread 13 started at time 00:00:03.0099824 
Thread 14 started at time 00:00:04.0100671 
Thread 15 started at time 00:00:05.0098035 
Thread 16 started at time 00:00:06.0099449 
Thread 17 started at time 00:00:07.0096293 
Thread 18 started at time 00:00:08.0106774 
Thread 19 started at time 00:00:09.0098193 
Thread 20 started at time 00:00:10.0104156 
Thread 3 started at time 00:00:10.0109315 
Thread 8 started at time 00:00:10.0112171 
Thread 7 started at time 00:00:10.0112531 
Thread 9 started at time 00:00:10.0117256 
Thread 4 started at time 00:00:10.0117920 
Thread 10 started at time 00:00:10.0117298 
Thread 6 started at time 00:00:10.0109381 
Thread 5 started at time 00:00:10.0112276 
Thread 21 started at time 00:00:11.0095859 
Thread 11 started at time 00:00:11.0101189 
Thread 22 started at time 00:00:12.0095421 
Thread 12 started at time 00:00:12.0111173 
Thread 23 started at time 00:00:13.0095932 ... 

注:私のシステムで

int workers, ports; 
ThreadPool.GetMinThreads(out workers, out ports); 
Console.WriteLine("Min workers = " + workers); // Prints 8 on my system. 
var sw = Stopwatch.StartNew(); 

for (int i = 0; i < 100; ++i) 
{ 
    Task.Run(() => 
    { 
     Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} started at time {sw.Elapsed}"); 
     Thread.Sleep(10000); 
    }); 
} 

Console.ReadLine(); 

、これは次のように出力しますスレッドの最初のバッチが終了してから再利用できるまで、毎秒約1回までです。

このエフェクトは、スレッドの終了に比較的長い時間がかかる場合にのみ発生します。

+0

ニース。どうもありがとう。 –

+1

"それはあまりにも多くのスレッドを起動する" - 私はそれが本当であるか分からない。あなたは詳しく説明できますか? –

+0

@shay__ファイルの各行に対して 'Task.Run()'を呼び出すと、1行に1つのスレッドを起動しようとします。いくつかのスレッドの後に、スレッドごとに0.5秒の遅延が導入されます。単純なテストでは、新しいスレッドが作成され再利用される前に前のスレッドが終了するため、多数のスレッドを作成できません。しかし、各行の処理が十分に遅い場合、スレッドの数は増加し続けるでしょう。 –

関連する問題