4

我有一个我想异步调用的方法:

void Foo()
{
}

我确实可以通过以下方式异步调用它:

delegate void DVoidMethod();
DVoidMethod FooDelegate = new DVoidMethod(Foo);
FooDelegate.BeginInvoke(null,null);

有没有人有其他选择?

我觉得三行代码太多了?

4

6 回答 6

10

免责声明:

不要在实际代码中使用它。这只是试图缩短提到的代码 OP。要在不返回结果的情况下进行真正的异步调用,请使用:

ThreadPool.QueueUserWorkItem(stateObject => Foo());

在框架中使用Action和委托:Func

new Action(Foo).BeginInvoke(null, null);

Action<T>自 2.0 以来一直存在。3.5 中添加了其他变体。但是,在 2.0 上,您可以在某处手动声明一堆以供进一步使用;甚至更好,使用LINQBridge

于 2009-07-08T15:51:47.387 回答
8

怎么样:

ThreadPool.QueueUserWorkItem(new WaitCallback((o) => Foo()));

更新以考虑较新版本的 .net 中可用的 TPL API:

.Net 4及更高版本中,您可以执行以下操作:

Task.Factory.StartNew(() => Foo());

.Net 4.5及更高版本中,您还可以执行以下操作:

Task.Run(() => Foo());

Task.Factory.StartNewTask.Run之间的区别在于,“StartNew”方法有一些额外的参数,可以让您传递状态、任务创建选项和调度程序,以便在需要时为您提供一些额外的控制。

于 2009-07-08T15:54:20.530 回答
3

您可以将其分解为两行(在 .Net 1.1及更早版本中),只需:

delegate void DVoidMethod();
new FooDelegate(DVoidMethod).BeginInvoke(null, null)

但在 2.0 及更高版本中……Mehrdad 的语法有效。

请参阅 MSDN 上 2.0 及更高版本的操作委托:

http://msdn.microsoft.com/en-us/library/018hxwa8(VS.80).aspx

于 2009-07-08T15:54:08.533 回答
3

如果不使用 Action 和 Func,您可以在 void () 委托的情况下使用 MethodInvoker:

new MethodInvoker(Foo).BeginInvoke(null, null);

另外,应该注意的是,如果您使用 BeginInvoke 方法,则必须在委托完成执行时调用 EndInvoke。因此,上面的这一行必须更改为使用回调,或者您需要保留对委托的引用。 . 像这样:

MethodInvoker mi = null;
IAsyncResult ar = null;

ar = (mi = new MethodInvoker(Foo)).BeginInvoke(null,null);


.. sometime later after the delegate has completed executing
mi.EndInvoke(ar);

每当您使用 BeginInvoke 时都是如此。所以我想最后我不会推荐使用 BeginInvoke 方法..

@Steven 使用 ThreadPool的解决方案在我看来是一个更好的解决方案.. 和他的 oviously:)

于 2009-07-08T15:59:46.730 回答
1

严格来说,从性能的角度来看,我不会担心代码行数,因为您不知道您正在调用的函数背后有多少实际代码。

于 2009-07-08T17:14:26.517 回答
1

旧线程,但我无法抗拒堆积。

您确实必须调用 EndInvoke 以避免泄漏,即使您没有使用结果或对方法的完成做出反应。但这并不意味着它必须是丑陋的。

BeginInvoke 需要 AsyncCallback 作为回调参数。AsyncCallback 的签名是一个带有 IAsyncResult 的 void。EndInvoke 具有该签名,因此:

    //waste some time...
    void Foo() {}
    void InvokeFoo()
    {
        Action fooer = () => Foo();
        fooer.BeginInvoke(fooer.EndInvoke, null);            
    }
    void InvokeFoo2()
    {
        // or, less concise but some consider more readable:
        Action fooer = new Action(Foo); //...invoke doesn't change
    }
于 2010-02-10T16:58:06.043 回答