-2

約 170.000 個のファイルを処理する必要があり、複数のスレッドを使用したいと考えています。ファイルの名前は、Year-Number 形式に従って連続しており、フォルダ内で年ごとにソートされています。(ただし、それらはすべて同じフォルダーに入れることができます)。年が異なれば、ファイル数も異なります。ファイルのサイズは小さく、それぞれわずか数 (10<サイズ<20) KB です。

処理タスクの出力は SQL データベースに格納されるため、それらが処理される順序は重要ではありません。これには何が最善の方法でしょうか?同じファイルを 2 回開かずに?

4

5 に答える 5

1

考えられる解決策の1つは、生産者/消費者の設計パターンを使用することです。

プロデューサーはファイルのリストを取得し、ProducerConsumerキューにフィードします。コンシューマーは、キューから取得したファイル(またはファイルパス)を処理して処理します(データベースに挿入します)。このアプローチでは、すべてのファイルが1回だけ処理されます。

ProducerConsumerキューの問題は、 C#のプロデューサー/コンシューマーのSOの質問で説明されています。

編集

ただし、タスクは複雑になる可能性があります。

  • 既存のファイルの1つが変更された場合はどうなりますか。新しいファイルの内容でデータベースを更新する必要がありますか?その場合、ファイルが変更されたことを示す「マーカー」のメカニズムが必要になります(ファイルの最終更新日が機能する場合があります)
  • プロセス中に新しいファイルが追加された場合はどうなりますか。等
于 2013-01-14T16:18:50.820 に答える
0

ここに小さな例があります:

public static class FilesProcessor
{
    private static List<FileProcessor> m_FileProcessors;

    public static void Start()
    {
        m_FileProcessors = new List<FileProcessor>();

        for (Int32 year = 2005; year < DateTime.Now.Year; ++year)
            InstanciateFileProcessor(year);

        while (!FinishedLoading())
            Application.DoEvents();
    }

    public static void Stop()
    {
        foreach (FileProcessor processor in m_FileProcessors)
            processor.Stop()

        m_FileProcessors.Clear();
        m_FileProcessors = null;
    }

    private static Boolean FinishedLoading()
    {
        foreach (FileProcessor processor in m_FileProcessors)
        {
            if (processor.IsAlive() && !processor.FinishedLoading())
                return false;
        }

        return true;
    }

    private static void InstanciateFileProcessor(Int32 year)
    {
        FileProcessor processor = new FileProcessor(year);
        processor.Start();

        m_FileProcessors.Add(processor);
    }
}

次に、FileProcessorクラス:

public sealed class FileProcessor
{
    private Int32 m_Year;

    public Boolean IsAlive()
    {
        return ((m_Thread != null) && m_Thread.IsAlive);
    }

    public Boolean FinishedLoading()
    {
        return ((m_Thread == null) || m_Thread.Join(10));
    }

    public FileProcessor(Int32 year)
    {
        m_Year = year;

        m_Thread = new Thread(Load);
        m_Thread.Name = "Background File Processor";
    }

    public void Start()
    {
        if (m_Thread != null)
            m_Thread.Start();
    }

    public void Stop()
    {
        if ((m_Thread != null) && m_Thread.IsAlive)
            m_Thread.Abort();
    }

    private void Load()
    {
        // Browse the Year folder...
        // Get and read all fines one by one...
    }
}
于 2013-01-14T16:22:12.180 に答える
0

.Netの並列クラスを使用することの何が問題になっていますか?

コレクションを並列foreachループに渡すだけです。.Netがすべての割り当てを行います。カスタムパーティショナーを渡して、チャンクパーティショニングを使用することもできます。チャンクパーティショニングにより、スレッドはさらに多くのタスクを要求し続けます。チャンクパーティショニングを使用しない場合、すべての作業が事前に割り当てられ、一部のタスクに他のタスクよりも時間がかかると、パフォーマンスが低下する可能性があります(1つのスレッドがまだ作業を行っている間に、一部のスレッドがアイドル状態になる可能性があります)。

http://msdn.microsoft.com/en-us/library/dd460720.aspx

于 2013-01-14T16:47:29.587 に答える
0

1年に1スレッドだと思います。各「YearThread」は、その年番号で始まるファイルを読み取り、それらを順次読み取ります。データベースに行くことに関しては、私はあなたにどちらかを提案したいと思います

  • すべてが1つのテーブルに移動する場合は、インデックスを削除してインデックスロックが発生しないようにし、後でインデックスを作成します
  • インデックスを削除できない場合は、少なくとも行のロックと、タイムアウトする前のトランザクションの待機期間を使用してください(2つ以上のスレッドが同時に挿入されている可能性があります)

別の解決策は、スレッドがファイルへの挿入ステートメントを生成し、そのファイルを実行して挿入を実行することです。または、一括挿入ツールを使用することもできます。ただし、これはテーブル構造とDBMSによって異なります

于 2013-01-14T16:19:38.650 に答える
0

ここでは、2 つの可能なアプローチを見ることができます。

まず、問題を 2 つに分割します。1 - 何を処理するかを考えます。2 - 処理を行います。パート 1 はおそらく単独で実行する必要があるため、処理が必要なものの 100% 正確なリストが得られます。次に、リストの分割と複数のスレッドの導入に関して、凝った (またはあまり凝っていない) ロジックを実装できます。

次に、@CarlosGrappa が提案するものと同様のことを行います。したがって、基本的には、独自の「事前にプログラムされた」フィルターを使用して各スレッドを作成します。カルロスが示唆するように、それはその年かもしれません。または、ファイルのタイムスタンプの 1 時間ごとに 1 つずつ、合計 24 のスレッドを作成することもできます。または、60 個のスレッドがあり、それぞれが正時を過ぎた特定の分を調べます。基本的には、(a) 負荷をできるだけ均等に分割するための明確な基準と、(b) データ ファイルが 1 回だけ処理されることを保証するための明確な基準を与えるものであれば何でもかまいません。

明らかに、これらのアプローチの 2 番目の方がより高速に実行されますが、ファイルを分割する方法については、さらに考慮する必要があります。最初の方法では、完全なリストを取得したら、基本的に、プロセッサで一度に 100 個、1000 個、または 10000 個などのファイルをチャックすることができます。

于 2013-01-14T16:36:00.157 に答える