2

クラスの新しいインスタンスを作成し、画像を操作してディスクに保存する並列 foreach 関数があります...

ただし、400 回のうち約 4 回、画像はディスクに保存されますが、操作されていない場合、私の理論では、それが発生した場合、クラスに存在するプロパティの一部はサポートされていない場合に null になります...

4 つ (場合によっては 3 つ) のエラーは、ほとんどが並列ループの最初の 10 枚の画像で発生します。

エラーメッセージはありません。何らかの理由でコードの一部をスキップするだけです...並列の場合、ブレークポイントが機能しないため、デバッグが困難です。

続行/デバッグ/修正する方法について何かアドバイスはありますか?

要求されたコード

    private static void GenerateIcons(Effects effect)
    {
        DirectoryInfo dir = new DirectoryInfo(HttpContext.Current.Server.MapPath(@"~\Icons\Original\"));

        FileInfo[] ff = dir.GetFiles();

        string mappath = HttpContext.Current.Server.MapPath(@"~\Icons\");

        List<string> paths = new List<string>();

        string ids = GetAllEffectIds(effect.TinyUrlCode);

        Parallel.ForEach(ff, item =>
        {
            if (!File.Exists(mappath + @"Generated\" + ids + "-" + item.Name))
            {
                paths.Add(mappath + @"Generated\" + ids + "-" + item.Name);
                ApplyEffects f = new ApplyEffects(effect, item.Name, mappath);
                f.SaveIcon();


            }
        });
        //Zip icons!
        ZipFiles(paths, effect.TinyUrlCode, ids, effect.General.Prefix);

    }
4

3 に答える 3

1

List<T>私の理論では、スレッドセーフではないため、パスのリストが適切に更新されていません。基本的に、2 つのスレッドが同時に項目をリストに追加しようとすると、結果のリストから 4 つの項目が欠落するなど、多くの奇妙なことが発生する可能性があります。lock ステートメントを使用してみてください。

Parallel.ForEach(ff, item =>
{
    if (!File.Exists(mappath + @"Generated\" + ids + "-" + item.Name))
    {
        lock(paths) 
        {
            paths.Add(mappath + @"Generated\" + ids + "-" + item.Name);
        }
        ApplyEffects f = new ApplyEffects(effect, item.Name, mappath);
        f.SaveIcon();
    }
});
于 2012-06-20T13:00:33.447 に答える
1

うまくいけばスレッドの問題を取り除くために、より機能的なスタイルで書き直すことができます:

private static void GenerateIcons(Effects effect)
{
    var dir     = new DirectoryInfo(HttpContext.Current.Server.MapPath(@"~\Icons\Original\"));
    var mappath = HttpContext.Current.Server.MapPath(@"~\Icons\");
    var ids     = GetAllEffectIds(effect.TinyUrlCode);

    var filesToProcess = dir
        .EnumerateFiles()
        .AsParallel()
        .Select(f => new { info = f, generated = File.Exists(mappath + @"Generated\" + ids + "-" + f.Name) })
        .ToList();

    Parallel.ForEach(filesToProcess.Where(f => !f.generated), file =>
    {
        new ApplyEffects(effect, file.info.Name, mappath).SaveIcon();
    });

    //Zip icons!
    ZipFiles(filesToProcess.Select(f => f.info), effect.TinyUrlCode, ids, effect.General.Prefix);
}
于 2012-06-20T13:35:01.470 に答える
0
  1. 非並列版で確認しましたか?

  2. スレッドセーフとしてマークされていない API 関数を使用していますか?

1) に答えるには、ミューテックスは関数全体をロックし、エラーをテストします。

2 に答えるには、問題のある関数が見つかるまでミューテックスのコード量を減らします。二分法でこれを行うことができます。

ConcurrentBag<T>スレッドセーフなコンテナです。

于 2012-06-20T12:57:04.447 に答える