C# 没有EndInvoke的异步调用?
以下面的类为例C# 没有EndInvoke的异步调用?,c#,asynchronous,delegates,action,C#,Asynchronous,Delegates,Action,以下面的类为例 public class A { // ... void Foo(S myStruct){...} } public class B { public A test; // ... void Bar() { S myStruct = new S(); test.Foo(myStruct); } } 现在,我希望方法调用test.Foo(myStruct)是一个异步调用('fire-and-forget')。ba
public class A
{
// ...
void Foo(S myStruct){...}
}
public class B
{
public A test;
// ...
void Bar()
{
S myStruct = new S();
test.Foo(myStruct);
}
}
现在,我希望方法调用test.Foo(myStruct)是一个异步调用('fire-and-forget')。bar方法需要尽快返回。关于委托、BeginInvoke、EndInvoke、线程池等的文档并不能帮助我找到解决方案
这是一个有效的解决方案吗
// Is using the `EndInvoke` method as the callback delegate valid?
foo.BeginInvoke(myStruct, foo.EndInvoke, null);
我想说,您最好的选择是使用
线程池
:
void bar()
{
ThreadPool.QueueUserWorkItem(o=>
{
S myStruct = new S();
test.foo(myStruct);
});
}
这将使代码段排队,以便在单独的线程中执行。现在,您还必须注意一些其他事项:如果有多个线程访问A
的同一个实例,并且该实例修改了一个变量,那么您必须确保正确同步该变量
public class A
{
private double sum;
private volatile bool running;
private readonly object sync;
public A()
{
sum = 0.0;
running = true;
sync = new object();
}
public void foo(S myStruct)
{
// You need to synchronize the whole block because you can get a race
// condition (i.e. running can be set to false after you've checked
// the flag and then you would be adding the sum when you're not
// supposed to be).
lock(sync)
{
if(running)
{
sum+=myStruct.Value;
}
}
}
public void stop()
{
// you don't need to synchronize here since the flag is volatile
running = false;
}
}
您可以使用解释过的回调模型@ 这样,EndInvoke将不在bar()中,而是在一个单独的回调方法中
在本例中,EndRead(对应于EndInvoke的是CompleteRead回调方法,而不是对应于bar的TestCallbackAPM调用方法)您不需要调用
EndInvoke
;不叫它仅仅意味着:
- 您无法从该方法获取返回值
- 在方法执行期间抛出的任何异常都将消失
var del = new Action(foo.Bar);
del.BeginInvoke(iar =>
{
try
{
del.EndInvoke(iar);
}
catch (Exception ex)
{
// Log the message?
}
}, null);
执行此代码时会发生以下情况:
del
和匿名委托(iar=>…
)del
EndInvoke
时,返回方法的结果,或者抛出异常(如果发生异常)// This is pointless and is still, essentially, synchronous.
del.EndInvoke(del.BeginInvoke(null, null));
编辑:您应该始终调用End*
。我从来没有发现过不调用它会出现问题的场景,但是这是一个实现细节,并且非常复杂
最后,如果抛出异常,您的解决方案将使进程崩溃,如果您不关心异常,只需将null作为委托传递(del.BeginInvoke(myStruct,null,null);
)。因此,作为最后一个示例,您要寻找的可能是:
public class A
{
// ...
void Foo(S myStruct){...}
void FooAsync(S myStruct)
{
var del = new Action<S>(Foo);
del.BeginInvoke(myStruct, SuppressException, del);
}
static void SuppressException(IAsyncResult ar)
{
try
{
((Action<S>)ar.AsyncState).EndInvoke(ar);
}
catch
{
// TODO: Log
}
}
}
公共A类
{
// ...
void Foo(S myStruct){…}
void fooancy(S myStruct)
{
var del=新动作(Foo);
del.BeginInvoke(myStruct、SuppressException、del);
}
静态无效抑制异常(IAsyncResult ar)
{
尝试
{
((Action)ar.AsyncState).EndInvoke(ar);
}
抓住
{
//TODO:日志
}
}
}
这是一个选项:
ThreadPool.QueueUserWorkItem(bcl =>
{
var bcList = (List<BarcodeColumn>)bcl;
IAsyncResult iftAR = this.dataGridView1.BeginInvoke((MethodInvoker)delegate
{
int x = this.dataGridView1.Rows[0].Cells.Count - 1;
for (int i = 0; i < this.dataGridView1.Rows.Count - 1; i++)
{
try
{
string imgPath = bcList[i].GifPath;
Image bmpImage = Image.FromFile(imgPath);
this.dataGridView1.Rows[i].Cells[x].Value =bmpImage;
}
catch (Exception)
{
continue;
}
}
});
while (!iftAR.IsCompleted) { /* wait this*/ }
}, barcodeList);
ThreadPool.QueueUserWorkItem(bcl=>
{
var bcList=(List)bcl;
IAsyncResult iftAR=this.dataGridView1.BeginInvoke((MethodInvoker)委托
{
int x=this.dataGridView1.Rows[0].Cells.Count-1;
对于(int i=0;i
True,不“要求”调用EndInvoke
,但如果不这样做,将导致内存泄漏@马特克莱恩:不,没有。SLaks的回答有些正确,但在某些情况下,一些跟踪是通过Begin/End Invoke
对来完成的-一个例子是:如果你不在Socket
操作上调用EndInvoke
,你的Socket性能计数器将完全失控(没有内存泄漏,这些值将非常不正确)。也许这将是一个有价值的评论,可以添加到SLaks的答案中。它可能会帮助其他人,因为根据此线程,这是“必须调用EndInvoke()”的正确方法。如果不需要返回值,是否可以传递null而不是回调方法?我想情况就是这样