2013-03-11 53 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,Action会在工作流完成之前返回。

我对WaitHandle很熟悉,但感觉就像一个klunky解决方案。

任何帮助/指导表示赞赏。

+0

我还没有想法,但我有兴趣看到一个答案。我用waithandles - 而我不喜欢它们。感觉“粗呃”比GOTO: – 2013-03-13 01:16:11

回答

1

WaitHandle是一个抽象类,提供了在操作系统级别等待访问共享资源的能力。如果您希望在此级别同步访问,则不会放弃使用它。但是,正如您所提到的,使用类似ManualResetEvent的东西可能会中断代码的流向,从而在出现问题时很难进行阅读和诊断。

.NET框架最近增加了很多关于线程的尝试来解决这个问题。在.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); 
    } 
} 
相关问题