2013-03-11 1 views
1

MVC 응용 프로그램에서 작업 중이며 자동화 작업을 위해 백그라운드에서 Windows Workflow를 사용합니다.WaitHandle이 최상의 옵션입니까?

워크 플로우가 완료되기를 기다리는 코드를 구현했습니다. 아래는 문제를 중요한 부분에 집중시키는 샘플 앱입니다.

문제는 실제로 WF 작업에서 진행중인 작업과 관련이 없지만 완료하는 방법을 더 많이 알게되었습니다.

HomeController.cs

public ActionResult Index() 
     { 
      return View(); 
     } 

     [HttpPost] 
     public JsonResult ProcessRequest() 
     { 
      int[] arr = new int[0]; 

      var wh = new ManualResetEvent(false); 
      var instance = new Activities.SampleCodeActivity(); 
      var args = new Dictionary<string, object>(); 
      args.Add("Limit", 25); 
      var app = new WorkflowApplication(instance, args); 
      app.Completed = resultArgs => 
      { 
       var list = (List<int>)resultArgs.Outputs["Primes"]; 
       arr = list.ToArray(); 
       wh.Set(); 
      }; 
      app.Run(); 
      wh.WaitOne(); 
      return Json(arr); 
     } 

Index.cshtml

@{ ViewBag.Title = "Index"; } 

<script src="../../Scripts/jquery-1.7.1.min.js"></script> 
<script type="text/javascript"> 
    var tools = {}; 
    tools.processRequest = function() { 
     $.ajax({ 
      url: "@Url.Action("ProcessRequest")", type: "POST", 
      success: function (data) { 
       alert(data); 
      } 
     }); 
    }; 
    $(document).ready(function() { 
     tools.processRequest(); 
    }); 
</script> 
<h2>Index</h2> 

SampleCodeActivity.cs

public class SampleCodeActivity : CodeActivity 
{ 
    public InArgument<int> Limit { get; set; } 
    public OutArgument<List<int>> Primes { get; set; } 
    private List<int> _list = new List<int>(); 
    protected override void Execute(CodeActivityContext context) 
    { 
     var limit = context.GetValue(Limit); 
     checkForPrimes(limit); 
     context.SetValue(Primes, _list); 
    } 

    private void checkForPrimes(int limit) 
    { 
     for (var x = 2; x <= limit; x++) 
      if (isPrime(x)) _list.Add(x); 
    } 
    private bool isPrime(int value) 
    { 
     for (var x = value - 1; x > 1; x--) 
      if (value % x == 0) return false; 
     return true; 
    } 
} 

내 질문은 Controller Action의 WaitHandle/ManualResetEvent에 관한 것입니다. 작업 등을 사용하여이를 구현하는 더 좋은 방법이 있습니까? .NET 4.5 사용하고 있습니다.

WaitHandle이 제자리에 없으면 작업 흐름이 완료되기 전에 작업이 반환됩니다.

저는 WaitHandle에 익숙하지만 괴상한 해결책이라고 생각합니다.

도움/안내를 부탁드립니다.

+0

나는 생각이 없지만 대답을 얻고 싶습니다. 나는 waithandles를 사용한다 - 나는 그들을 좋아하지 않는다. GOTO보다 "거친"느낌 : –

답변

1

WaitHandle은 운영 체제 수준에서 공유 리소스에 대한 액세스를 대기하는 기능을 제공하는 추상 클래스입니다. 이 수준에서 액세스를 동기화하려면 사용하지 않아도됩니다. 그러나 언급했듯이 ManualResetEvent과 같은 것을 사용하면 코드 흐름이 중단되어 상황이 잘못 될 때 읽고 진단하기가 어려워 질 수 있습니다.

최근 .NET Framework에 대한 추가 사항 중 스레드를 사용하여이 문제를 해결하려는 시도가 많습니다. .NET 4에서는 Task이라는 개념이 도입되어 코드를 다소 간소화 할 수 있었으며 C# 5는 해당 인프라의 상단에 구축하여 async/await 키워드를 도입했습니다. 아래 코드는 간단한 콘솔 응용 프로그램으로, ManualResetEvent, Taskasync/await을 사용하여 원하는 것을 달성하는 세 가지 방법을 보여줍니다.

세 가지 모두 스레드를 동기화하기 위해 어느 수준에서 WaitHandle 클래스를 사용하지만, Taskasync/await을 사용하여 가독성이 향상된다는 사실을 깨닫는 것이 중요합니다.

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<int> results; 

     //Using raw Wait Handle 
     ManualResetEvent handle = new ManualResetEvent(false); 
     Thread thread = new Thread(o => 
      { 
       //Long running process 
       results = LongRunningTask(); 
       handle.Set(); 
      }); 
     thread.Start(); 
     handle.WaitOne(); 

     Console.WriteLine("Thread completed"); 

     //Using Tasks 
     Task<List<int>> task = Task<List<int>>.Factory.StartNew(LongRunningTask); 
     results = task.Result; 
     Console.WriteLine("Task completed"); 

     //Using async/await 
     results = LongRunningTaskAsync().Result; 
     Console.WriteLine("Async Method completed"); 

     Console.ReadLine(); 
    } 

    public static List<int> LongRunningTask() 
    { 
     Thread.Sleep(5000); 
     return new List<int>(); 
    } 

    public static async Task<List<int>> LongRunningTaskAsync() 
    { 
     return await Task<List<int>>.Factory.StartNew(LongRunningTask); 
    } 
}