Why is my BeginInvoke method not async?
In order to avoid freezing of GUI, I wanted to run method connecting to DB asynchronously. Therefore I have written this:
DelegatLoginu dl = ConnectDB;
IAsyncResult ar = dl.BeginInvoke(null,开发者_Go百科 null);
var result = (bool)dl.EndInvoke(ar);
But it is still freezing and I do not understand why. I thought BeginInvoke
ensures the invoked code runs in another thread. Thank you!
Calling EndInvoke() will block until the BeginInvoke() call has completed.
You need this kind of pattern in order for your long-running method to invoke a callback when it finishes:
public void DemoCallback()
{
MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
string s ;
int iExecThread;
// Create the callback delegate.
AsyncCallback cb = new AsyncCallback(MyAsyncCallback);
// Initiate the Asynchronous call passing in the callback delegate
// and the delegate object used to initiate the call.
IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, cb, dlgt);
}
public void MyAsyncCallback(IAsyncResult ar)
{
string s ;
int iExecThread ;
// Because you passed your original delegate in the asyncState parameter
// of the Begin call, you can get it back here to complete the call.
MethodDelegate dlgt = (MethodDelegate) ar.AsyncState;
// Complete the call.
s = dlgt.EndInvoke (out iExecThread, ar) ;
MessageBox.Show (string.Format ("The delegate call returned the string: \"{0}\",
and the number {1}", s, iExecThread.ToString() ) );
}
See the description of EndInvoke
here, specifically:
The EndInvoke() function is used to retrieve the results of the asynchronous call. It can be called anytime after BeginInvoke(). If the asynchronous call has not completed yet, EndInvoke() blocks until it completes.
You're immediately blocking your UI thread when calling dl.EndInvoke(ar)
. This kind of defeats the whole purpose of having an async call.
There's 4 different patterns to using the async model in .NET as this question covers very well.
You're using the "I'll call you" approach. However if you want to wait until the work item has finished, the best technique is to use a Mutex
(the WaitHandle
):
void Run()
{
Action<string> doWork = DoWork;
IAsyncResult result = doWork.BeginInvoke("I will call you", null, null);
// You "call the method" - wait 10 seconds for the method to finish.
bool success = result.AsyncWaitHandle.WaitOne(10 * 1000);
}
void DoWork()
{
}
I suspect you don't want to block, in which case "fire and forget" causes the least headaches.
Specify a method to be called when the call is completed in BeginInvoke (like dl.BeginInvoke(null, OnConnectCompleted)). Then the thread will not be blocked.
Why not just use a BackgroundWorker instead?
Call to EndInvoke will block your current thread. You should pass a delegate into the BeginInvoke instead of calling the EndInvoke
精彩评论