2012-03-16 4 views
2

임 로딩 최대의 웹 페이지 (면도기) 및 (내 세계) 때문에, 지금이실행 여러 병렬

var webPage = WebPage.CreateInstanceFromVirtualPath(_relativeFilePath); 

var httpContext = new HttpContextWrapper(HttpContext.Current); 
var startPage = StartPage.GetStartPage(webPage, "_PageStart", new[] { "cshtml" }); 
var pageContext = new WebPageContext(httpContext, webPage, startPage); 

var sb = new StringBuilder(); 
using (var writer = new StringWriter(sb)) 
{ 
    webPage.ExecutePageHierarchy(pageContext, writer); 
} 

string output = sb.ToString().Trim(); 

처럼 내 .cshtml 파일을 실행, 각 .cshtml 파일은 자체에 포함 된 단위는 내가한다 위에서 N 번 병렬로 실행되는 코드를 가질 수 있지만 드물 긴하지만 예외적 인 경우도 있습니다.

System.InvalidOperationException: Stack empty. 
    at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) 
    at System.Collections.Generic.Stack`1.Pop() 
    at System.Web.WebPages.TemplateStack.Pop(HttpContextBase httpContext) 
    at System.Web.WebPages.WebPageBase.ExecutePageHierarchy() 
    at System.Web.WebPages.WebPage.ExecutePageHierarchy(IEnumerable`1 executors) 
    at System.Web.WebPages.WebPage.ExecutePageHierarchy() 
    at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) 

병렬 처리를 비활성화하고 모든 .cshtml 파일을 하나씩 실행하면 예외가 트리거되지 않습니다. 따라서 WebPages의 내부 동작이 스레드로부터 안전하지 않은지 궁금해하며 ExecutePageHierarchy에 대한 각각의 호출이 현재 비 고유 값에 액세스하는 것일 수도 있습니다. HttpContext

답변

4

HttpContext 및 기타 ASP.NET 내장 객체는 일반적으로 스레드 독립적이지 않습니다. 여러 소비자에게 안전합니다. Razor 템플릿 엔진을 사용하여 여러 항목을 병렬로 처리하는 것이 목표라면 Razor 자체가 ASP.NET의 모든 것에 직접적인 종속성이 없기 때문에이 작업을 수행 할 수 있다고 생각합니다. 그러나 일단 .cshtml (System.Web.WebPages)을 사용하면 불행하게도 그 시점에서 ASP.NET의 내장 함수로 제한됩니다.

+0

일부는 TemplateStack가 HttpContext.Items에 정적 키를 사용하여 저장됩니다임을 밝혀 파고 이 예외가 Throw되는 이유 해결 방법은 Items 속성을 HttpContextWrapper의 하위 클래스로 분리하여 각 병렬 반복이 고유 한 스택을 갖도록하는 것입니다. 그게 효과가 있니? –

+1

@ Pouli가 작동 할 수도 있지만 매우 지원되지 않습니다. 당신이하는 일은 ASP.NET 내부 구조를 파헤 치고 작동 방식을 약간 바꿔서 결과를 예측할 수 없으며 시스템에 대한 가장 간단한 패치/변경/업그레이드로 깨질 수 있습니다. 따라서이 접근법을 권장하지 않습니다. CSHTML 페이지는 동일한 요청 내에서 병렬로 실행되지 않습니다. – Eilon

1

이 스레드를보고있는 다른 사용자에게만 허용됩니다. 나는 HttpContextBase와 HttpRequestBase 추상 클래스를 최소한으로 구현했다. 그런 다음 viewPage를 렌더링 할 때 실제 클래스 대신 새 클래스 인스턴스를 제공합니다. (나는 템플릿 프레임 워크를 사용하지 않은 이유는 내가 아직 팁 사람을 스레드 안전을 찾지 못한 것입니다?)

public class MockRequest : HttpRequestBase 
{ 
    public override bool IsLocal { get { return false; } } 
} 

public class MockHttpContext : HttpContextBase 
{ 
    private readonly IDictionary _items = new Hashtable(); 

    public override HttpRequestBase Request { get { return new MockRequest(); } } 

    public override IDictionary Items { get { return _items; } } 
}