簡體   English   中英

C#:向ASP.NET中的Parallel.ForEach()添加上下文

[英]C#: Adding context to Parallel.ForEach() in ASP.NET

我有一個帶靜態get屬性的靜態類,在這個屬性中,我這樣做:

// property body
{
    // HttpContext.Current is NOT null
    ...

    Parallel.ForEach(files, file =>
    {
        // HttpContext.Current is null
        var promo = new Promotion();
        ...
    });
    ...

    // HttpContext.Current is NOT null
}

在視圖使用此屬性之前,此靜態類不會進行類型初始化。

問題是,在Parallel.ForEach()創建new Promotion()時初始化的Promotion的靜態構造函數使用HttpContext.Current promo在此Parallel.ForEach()的范圍內實例化時, HttpContext.Currentnull ,因此new Promotion()會導致異常。

HttpContext.Current在靜態get屬性中不為null,因為在視圖使用它之前不會調用它(因此它有一個HttpContext.Current )。

如果Promotion在其實例中使用HttpContext.Current而不是靜態成員,我可能只是將HttpContext.Current傳遞給new Promotion()構造函數:

 var context = HttpContext.Current;
 Parallel.ForEach(files, file =>
 {
     var promo = new Promotion(context);
 });

但由於Promotion的static成員需要HttpContext.Current,我不能。 我可能會重新設計Promotion類來將需要它的靜態成員更改為實例成員,但它們是靜態的,原因是 - 如果必須在每個成員上定義所有靜態成員,則會有很大的性能損失。每次實例化new Promotion時的實例。

有什么可行的解決方法? 我沒有意識到HttpContext.CurrentParallel.ForEach()的范圍內是null。

HttpContext.Current為null,因為它在“非Web線程”中運行。 如果你使用new Thread(...)分叉一些代碼,它將完全相同。 TPL在某種程度上隱藏了這一點,但您仍然需要意識到Parallel.ForEach中的每次迭代都可能在不同的線程中運行,並相應地對其進行處理。

特別是,如果你想在web請求中使用某些類或方法(並且Parallel.ForEach就是這種用法),你就是不能使用HttpContext.Current。 解決方法是在構造函數中顯式傳遞HttpContext(或HttpContextBase以提高可測試性)(或作為方法參數)

簡而言之:你需要靜態地使用HttpContext.Current。

只需將Parallel.ForEach調用之外的任何上下文傳遞給依賴於所述上下文的內部調用的任何函數。

var context = HttpContext.Current;
Parallel.ForEach(items, item =>
    {
        DoSomething(item, context);
    }
);



private static void DoSomething(item, context = null) {
    if (context == null) context = HttpContext.Current;

    ...
}

我喜歡回退到null,所以我不必擔心一直在傳遞上下文。 我只確保記住我的函數在從另一個線程調用時需要上下文,然后我就把那個孩子打到了那里。

它不起作用,因為在foreach中創建了一個新線程,因此上下文為null。 即使創建一個方法DoSomething來設置當前上下文,上下文仍然是null。

正如Mauricio指出的那樣, HttpContext.Current依賴於當前正在執行的線程。 讓我感到不同的是, 靜態構造函數依賴於HttpContext.Current這樣一個固有的瞬態值,但也許這不是你的想法。

如果您可以更改Promotion類,那么這將是我考慮的第一個選項。

如果沒有,您需要以某種方式強制PromotionHttpContext.Current仍然有效的點上進行類型初始化。 要了解強制類型初始化的內容,請閱讀此Jon Skeet博客文章

一個選項可能是創建一個虛擬的Promotion對象,(在整個程序中只需一次就足夠了)。 如果這不是一個選項,您可以嘗試通過反射閱讀該屬性。 我不知道是否強制類型初始化,但我想是的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM