1

自動化のために舞台裏でWindowsワークフローを使用するMVCアプリケーションに取り組んでいます。

ワークフローが完了するまで待機するコードをいくつか実装しました。以下は、問題をその重要な部分に要約するサンプル アプリです。

この問題は、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);
        }

インデックス.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;
    }
}

私の質問は、コントローラ アクションの WaitHandle/ManualResetEvent に関するものです。タスクなどを使用してこれを実装するより良い方法はありますか? .NET 4.5 を使用しています。

WaitHandle が配置されていないと、ワークフローが完了する前にアクションが返されます。

私は WaitHandle に精通していますが、扱いにくいソリューションのように感じます。

ヘルプ/ガイダンスをいただければ幸いです。

4

1 に答える 1

2

WaitHandleオペレーティング システム レベルで共有リソースへのアクセスを待機する機能を提供する抽象クラスです。このレベルでアクセスを同期したい場合は、それを使用しない手はありません。ただし、言及したように、のようなものを使用するManualResetEventと、コードの流れが中断され、問題が発生したときに読み取りや診断が難しくなる可能性があります。

スレッドに関する最近の .NET フレームワークへの追加の多くは、この問題に対処しようとしています。.NET 4 では、コードをいくらか合理化できるという概念Taskが導入され、C# 5 はそのインフラストラクチャの上に構築されてasync/awaitキーワードを導入しました。以下のコードは単純なコンソール アプリケーションで、 、 、および を使用して目的を達成する 3 つの方法を示してManualResetEventTaskますasync/await

3 つすべてがWaitHandleスレッドを同期するために何らかのレベルでクラスを使用していることを理解することが重要ですが、 と を使用すると読みやすさが向上しTaskますasync/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);
    }
}
于 2013-05-22T09:37:51.280 に答える