2012-06-20 33 views
2

我有一個創建一個類,操縱圖片的新實例,並將其保存到磁盤並行的foreach功能...不可靠的並行循環失敗4,滿分400倍

然而約4倍出400,圖片被保存到磁盤,但沒有被操縱,我的理論是,當它發生時,我的班級中存在的一些屬性爲空,當他們不支持...

4 (有時3個)錯誤主要發生在並行循環的前10個圖像中。

沒有錯誤信息,它只是跳過我的一些代碼,出於某種原因......當它是parralel時,我的斷點不工作,所以很難調試。

有關如何進行/調試/修復的任何建議?

代碼的要求

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); 

    } 
+5

我會改變代碼的4號線應該修復它。 – ChaosPandion

+0

@ChaosPandion,我個人會在第400行這樣做。第4行對我來說看起來是正確的:-) –

+0

@ChaosPandion哈哈xD,但它是空的! – BjarkeCK

回答

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); 
} 
+0

哇,在這裏學習了很多其他的東西:)但是這段代碼實際上包含了大約40個錯誤的錯誤數......如果我鎖定了效果,並將它包裝在parralel中的所有內容中,它不會給出任何錯誤,但是它和非並行的foreach循環一樣慢。 – BjarkeCK

+0

欣賞你的代碼,謝謝! – BjarkeCK

+0

「應用效果」是做什麼的? –

0
  1. 你與無水貨版本檢查?

  2. 您是否在使用任何未被標記爲線程安全的 API函數?

要回答1),互斥鎖鎖定整個函數並測試錯誤。

要回答2)減少互斥體中的代碼量,直到找到違規函數。你可以通過平分來做到這一點。

ConcurrentBag<T>是一個線程安全的容器。

+0

謝謝你,awencer會仔細研究它,是的,它可以與非平行版本一起工作......快速的問題,線程安全嗎? – BjarkeCK

+1

從不同線程訪問相同數據的函數如果沒有適當的互斥鎖,可能不是線程安全的。請參閱http://www.albahari.com/threading/part2.aspx#_Mutex –

1

我的理論是,由於List<T>不是線程安全的,所以你的路徑列表沒有被正確更新。本質上,如果兩個線程嘗試向列表中添加一個項目,同時會發生任何數量的奇怪事情,例如結果列表中缺少4個項目。嘗試使用lock statement

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(); 
    } 
}); 
+0

鎖(路徑)不起作用,但我正在調查ApplyEffects中的代碼以查看是否有任何代碼不是線程安全的。謝謝你的提示。 – BjarkeCK

+0

@BjarkeCK - 儘管這不是一個解決方案,但您應該熟悉線程安全集合。 – ChaosPandion