1

foreach を使用すると約 65 k、Parallel.ForEach を使用すると 3 GB を超えるファイルを取得する理由を簡単な言語で説明してもらえますか?

foreach のコード:

// start node xml document
var logItems = new XElement("log", new XAttribute("start", DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss")));
var products = new ProductLogic().SelectProducts();
var productGroupLogic = new ProductGroupLogic();
var productOptionLogic = new ProductOptionLogic();
// loop through all products
foreach (var product in products)
{
    // is in a specific group
    var id = Convert.ToInt32(product["ProductID"]);
    var isInGroup = productGroupLogic.GetProductGroups(new int[] { id }.ToList(), groupId).Count > 0;
    // get product stock per option
    var productSizes = productOptionLogic.GetProductStockByProductId(id).ToList();
    // any stock available
    var stock = productSizes.Sum(ps => ps.Stock);
    var hasStock = stock > 0;
    // get webpage for this product
    var productUrl = string.Format(url, id);
    var htmlPage = Html.Page.GetWebPage(productUrl);
    // check if there is anything to log
    var addToLog = false;
    XElement sizeElements = null;
    // if has no stock or in group
    if (!hasStock || isInGroupNew)
    {
        // page shows => not ok => LOG!
        if (!htmlPage.NotFound) addToLog = true;
    }
    // if page is ok
    if (htmlPage.IsOk)
    {
        sizeElements = GetSizeElements(htmlPage.Html, productSizes);
        addToLog = sizeElements != null;
    }
    if (addToLog) logItems.Add(CreateElement(productUrl, htmlPage, stock, isInGroup, sizeElements));
}
// save
var xDocument = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XElement("log", logItems));
xDocument.Save(fileName);

並列コードの使用は小さな変更で、foreach を Parallel.ForEach に置き換えただけです。

// loop through all products
Parallel.ForEach(products, product =>
{
    ... code ...
};

メソッド GetSizeElements と CreateElements はどちらも静的です。

update1 メソッド GetSizeElements および CreateElements をロック付きでスレッドセーフにしましたが、これも役に立ちません。

update2 問題を解決するための回答が得られました。いいですよね。しかし、このコードが foreach ソリューションよりもはるかに大きなファイルを作成する理由について、さらに洞察を得たいと思います。スレッドを使用するときにコードがどのように機能するかについて、もう少し理解を深めようとしています。そうすれば、より多くの洞察が得られ、落とし穴を回避する方法を学ぶことができます。

4

2 に答える 2

2

1つのことが際立っています:

if (addToLog) 
  logItems.Add(CreateElement(productUrl, htmlPage, stock, isInGroup, sizeElements));

logItemsトレッドセーフではありません。それがあなたの中心的な問題かもしれませんが、他にも多くの可能性があります。

出力ファイルがあるので、違いを探します。

于 2013-10-21T11:16:27.197 に答える
1

foreach ループ内で次のパラメーターを定義してみてください。

var productGroupLogic = new ProductGroupLogic();
var productOptionLogic = new ProductOptionLogic();

並列 foreach ループ内のすべてのスレッドで 2 つだけが使用され、結果が不必要に乗算されていると思います。

于 2013-10-21T11:30:38.827 に答える