Typesafe fire-and-forget asynchronous delegate invocation in C#

后端 未结 7 1794
陌清茗
陌清茗 2020-12-28 19:41

I recently found myself needing a typesafe \"fire-and-forget\" mechanism for running code asynchronously.

Ideally, what I would want to do is somet

相关标签:
7条回答
  • 2020-12-28 19:49

    Give this extension method a shot (per C# Is action.BeginInvoke(action.EndInvoke,null) a good idea?) to ensure no memory leaks:

    public static void FireAndForget( this Action action )
    {
        action.BeginInvoke(action.EndInvoke, null);
    }
    

    And you could use it with generic parameters as:

    T1 param1 = someValue;
    T2 param2 = otherValue;
    (() => myFunc<T1,T2>(param1,param2)).FireAndForget();
    
    0 讨论(0)
  • 2020-12-28 19:52

    I notice nobody's responded to this:

    I also can't run the code on the .NET thread pool because it may take a very long time to complete (it's advised to only run relatively short-lived code on the thread pool) - this makes it impossible to use the ThreadPool.QueueUserWorkItem().

    I'm not sure if you're aware of this, but async delegates actually do exactly this - they queue the work on a worker thread in the ThreadPool, exactly the same as if you did QueueUserWorkItem.

    The only time when async delegates behave differently is when they're special framework delegates like Stream.BeginRead or Socket.BeginSend. These use I/O completion ports instead.

    Unless you're spinning of hundreds of these tasks in an ASP.NET environment, I would recommend simply using the thread pool.

    ThreadPool.QueueUserWorkItem(s => action());
    

    Or, in .NET 4, you can use the task factory:

    Task.Factory.StartNew(action);
    

    (Note that the above will also use the thread pool!)

    0 讨论(0)
  • 2020-12-28 19:55

    How about something like:

    public static class FireAndForgetMethods
    {
        public static void FireAndForget<T>(this Action<T> act,T arg1)
        {
            var tsk = Task.Factory.StartNew( ()=> act(arg1),
                                             TaskCreationOptions.LongRunning);
        }
    }
    

    Use it like:

    Action<int> foo = (t) => { Thread.Sleep(t); };
    foo.FireAndForget(100);
    

    To add type safety, just expand out the helper methods. T4 is probably best here.

    0 讨论(0)
  • 2020-12-28 20:01

    You can pass EndInvoke as AsyncCallback for BeginInvoke:

    Action<byte[], int, int> action = // ...
    
    action.BeginInvoke(buffer, 0, buffer.Length, action.EndInvoke, null);
    

    Does that help?

    0 讨论(0)
  • 2020-12-28 20:07

    That clever chap Skeet approaches this subject here.

    There's a different approach to "fire and forget" about half way down.

    0 讨论(0)
  • 2020-12-28 20:11

    You could write your own threadpool implementation. It probably sounds like wore work than it would actually be. Then you don't have to abide by "only run relatively short-lived code" advisement.

    0 讨论(0)
提交回复
热议问题