5

Node.js koolaid を飲みながら、しばらく .NET デスクトップ プログラミングから離れていました。Node.js には、簡単に操作できる部分がいくつかあります。特に、スレッド モデルの単純さが気に入っています。また、単一のスレッドを追跡するコードを記述するだけで、マルチスレッド アプリケーションの利点をいくつか享受できることが気に入っています。

現在、.NET でマルチスレッド アプリケーションを作成する必要があり、 Node.js アプリケーションの構築に使用される同様のスレッド モデルを使用できない理由はないと思いました。特に、私はしたい:

  • コールバック パラメーターを使用して実行時間の長い関数を呼び出します。(その関数はプールからのスレッドで実行されます。おそらく、新しいスレッドで関数を呼び出す単純なラッパー関数で十分でしょうか?)
  • これらのコールバック関数呼び出しを「メイン」スレッドで実行して処理する
  • この「メイン」スレッドによってアクセスされるすべてのオブジェクトの自動同期を維持するため、ロックは問題になりません

このスレッド モデルのフレームワークは、.NET アプリケーション内または .NET アプリケーションに既に存在しますか? そうでない場合、私が探している機能の一部を既にサポートまたは処理している .NET の部分はありますか?

4

4 に答える 4

2

TPLをお勧めします。これがどのように機能するかの例です

Void Work()
{
    Task<string> ts = Get();
    ts.ContinueWith(t =>
        {
        string result = t.Result;
        Console.WriteLine(result);
        });
}

キャンセル、さまざまなスケジューラを使用したエラー処理など、さまざまな可能性があります。.Net 4.5 では、await を使用する可能性があります。

async void Work()
{ 
    Task<string> ts = Get(); 
    string result = await ts; 
    Console.WriteLine(result); 
}

ここで、コンパイラは async とマークされたメソッドを調べ、コードを読みやすくしたまま、スレッド セーフで堅牢なタス​​ク同期コードの山全体を追加します。

于 2012-09-25T05:56:58.220 に答える
1

.Net 4.0 で利用可能になった TPL (Task Parallel Library) を参照することをお勧めします。ポイント 1 と 2 は実行できますが、3 は実行できません。

http://msdn.microsoft.com/en-us/library/dd460717.aspxを参照してください。

于 2012-09-25T01:03:00.337 に答える
1

これは、Windows のネイティブ イベント ループを利用することで実現できます。

次のコードは同じ POC であり、言及した 3 つのポイントすべてに対応しています。ただし、これは単なる POC であることに注意してください。これは型安全ではなく、遅くなる可能性のある Delegate.DynamicInvoke を使用しますが、それでも概念を証明します。

public static class EventLoop
{
    private class EventTask
    {
        public EventTask(Delegate taskHandler) : this(taskHandler, null) {}

        public EventTask(Delegate taskHandler, Delegate callback)
        {
            TaskHandler = taskHandler;
            Callback = callback;
        }

        private Delegate Callback {get; set;}

        private Delegate TaskHandler {get; set;}

        public void Invoke(object param)
        {
            object[] paramArr = null;
            if (param.GetType().Equals(typeof(object[])))
            {
                paramArr = (object[]) param; //So that DynamicInvoke does not complain
            }

            object res = null;

            if (TaskHandler != null)
            {
                if (paramArr != null)
                {
                    res = TaskHandler.DynamicInvoke(paramArr);
                }
                else
                {
                    res = TaskHandler.DynamicInvoke(param);
                }
            }

            if (Callback != null)
            {
                EnqueueSyncTask(Callback, res);
            }
        }
    }

    private static WindowsFormsSynchronizationContext _syncContext;
    public static void Run(Action<string[]> mainProc, string[] args)
    {
        //You need to reference System.Windows.Forms
        _syncContext = new WindowsFormsSynchronizationContext();
        EnqueueSyncTask(mainProc, args);
        Application.Run();
    }

    public static void EnqueueSyncTask(Delegate taskHandler, object param)
    {
        //All these tasks will run one-by-one in order on Main thread
        //either on call of Application.DoEvenets or when Main thread becomes idle
        _syncContext.Post(new EventTask(taskHandler).Invoke, param);
    }

    public static void EnqueueAsyncTask(Delegate taskHandler, object param, Delegate callback)
    {
       //En-queue on .Net Thread Pool
       ThreadPool.QueueUserWorkItem(new EventTask(taskHandler, callback).Invoke, param);
    }
}

クライアントコード:

    [STAThread]
    static void Main(string[] args)
    {
        Thread.CurrentThread.Name = "MAIN THREAD";
        Console.WriteLine("Method Main: " + Thread.CurrentThread.Name);
        EventLoop.Run(MainProc, args);
    }

    static void MainProc(string[] args)
    {
        Console.WriteLine("Method MainProc: " + Thread.CurrentThread.Name);
        Console.WriteLine("Queuing Long Running Task...");
        EventLoop.EnqueueAsyncTask(new Func<int,int,int>(LongCalculation), new object[]{5,6}, new Action<int>(PrintResult));
        Console.WriteLine("Queued Long Running Task");

        Thread.Sleep(400); //Do more work
        EventLoop.EnqueueAsyncTask(new Func<int, int, int>(LongCalculation), new object[] { 15, 16 }, new Action<int>(PrintResult));
        Thread.Sleep(150); //Do some more work but within this time 2nd task is not able to complete, meanwhile 1st task completes

        //Long running Tasks will run in background but callback will be executed only when Main thread becomes idle
        //To execute the callbacks before that, call Application.DoEvents
        Application.DoEvents(); //PrintResult for 1st task as 2nd is not yet complete
        Console.WriteLine("Method MainProc: Working over-time!!!!");
        Thread.Sleep(500); //After this sleep, 2nd Task's print will also be called as Main thread will become idle
    }

    static int LongCalculation(int a, int b)
    {
        Console.WriteLine("Method LongCalculation, Is Thread Pool Thread: " + Thread.CurrentThread.IsThreadPoolThread);
        Console.WriteLine("Running Long Calculation");
        Thread.Sleep(500); //long calc
        Console.WriteLine("completed Long Calculation");
        return a + b;
    }

    static void PrintResult(int a)
    {
        Console.WriteLine("Method PrintResult: " + Thread.CurrentThread.Name);
        Console.WriteLine("Result: " + a);
        //Continue processing potentially queuing more long running tasks
    }

出力:

ここに画像の説明を入力

于 2012-09-27T12:55:04.717 に答える