.NET threads like Node.js / V8?

For some time I was out in .NET programming while drinking Node.js koolaid. There are some parts of Node.js. It’s easy for me to work. In particular, I like the simplicity of the streaming model, and I can have several advantages of a multithreaded application, but just write code to track a single stream.

Now I need to write a multi-threaded application in .NET, and it occurred to me that there is no reason why I cannot use the same one that is used to create Node.js applications . In particular, I want:

  • Calling long-term functions with callback parameters. (This function will be executed in the thread from the pool. Maybe a simple wrapper function is enough to call functions in new threads?)
  • So that these calls to the callback function are executed in the "main" thread for processing
  • Maintain automatic synchronization for all objects accessed by this "main" thread, so locking is not a problem.

Is there such an infrastructure for this threading model already inside or for .NET applications? If not, are there parts of .NET that already support or handle some of the functionality I'm looking for?

+5
source share
4 answers

I would recommend TPL. Here is an example of how this works.

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

There are a number of possibilities for cancellation, error handling using different schedulers, etc. With .Net 4.5 you have the option to use await

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

, async, , .

+2

, async/await - .NET. :

  • Task/Task<T>/TaskCompletionSource<T> JavaScript Deferred/Promise/Future.
  • , JavaScript .NET, .
  • JavaScript async/await. async , , , await. .
  • - Task.Run. , .NET , , , .
  • "" , TPL Rx. JS.

async/await .

+3

, , Window.

The following code is the POC for the same, and it addresses all three points that you mentioned. But note that this is just POC. This is not a safe type, and it uses Delegate.DynamicInvoke, which can be slow, but it still proves the concept.

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);
    }
}

Client code:

    [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 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
    }

Conclusion:

enter image description here

+1
source

All Articles