Consider this code:
class Program
{
static void Main(string[] args)
{
Master master = new Master();
master.Execute();
}
}
class TestClass
{
public void Method(string s)
{
Console.WriteLine(s);
Thread.Sleep(5000);
Console.WriteLine("End Method()");
}
}
class Master
{
private readonly TestClass test = new TestClass();
public void Execute()
{
Console.WriteLine("Start main thread..");
Action<String> act = test.Method;
IAsyncResult res = act.BeginInvoke("Start Method()..", x =>
{
Console.WriteLine("Start Callback..");
act.EndInvoke(x);
Console.WriteLine("End Callback");
}, null);
Console.WriteLine("End main thread");
Console.ReadLine();
}
}
We have result:
Start main thread..
End main thread
Start Method()..
End Method()
Start Callback..
End Callback
So, I want result:
Start main thread..
Start Method()..
End Method()
Start Callback..
End Callback
End main thread
How can I wait async
in this code? I checked MSDN article "Calling Synchronous Methods Asynchronously" and found this:
After calling BeginInvoke
you can do the following:
EndInvoke
to block until the call
completes.WaitHandle
using the IAsyncResultAsyncWaitHandle
WaitOne
method to block execution until theWaitHandle
is signaled, and then call EndInvoke
.IAsyncResult
returned by BeginInvoke
to determine when
the asynchronous call has completed, and then call EndInvoke
.BeginInvoke
. The method
is executed on a ThreadPool
thread when the asynchronous call
completes. The callback method calls EndInvoke
.I think better variant for me this second. But how implement this? In particular I'm interested overload WaitOne()
(Blocks the current thread until the current WaitHandle receives a signal). How correctly do it? I mean the common pattern in this case.
UPDATE:
Now I use Task<T>
:
class Program
{
static void Main(string[] args)
{
Master master = new Master();
master.Execute();
}
}
class WebService
{
public int GetResponse(int i)
{
Random rand = new Random();
i = i + rand.Next();
Console.WriteLine("Start GetResponse()");
Thread.Sleep(3000);
Console.WriteLine("End GetResponse()");
return i;
}
public void SomeMethod(List<int> list)
{
//Some work with list
Console.WriteLine("List.Count = {0}", list.Count);
}
}
class Master
{
private readonly WebService webService = new WebService();
public void Execute()
{
Console.WriteLine("Start main thread..");
List<int> listResponse = new List<int>();
for (int i = 0; i < 5; i++)
{
var task = Task<int>.Factory.StartNew(() => webService.GetResponse(1))
.ContinueWith(x =>
{
Console.WriteLine("Start Callback..");
listResponse.Add(x.Result);
Console.WriteLine("End Callback");
});
}
webService.SomeMethod(listResponse);
Console.WriteLine("End main thread..");
Console.ReadLine();
}
}
Main problem this is SomeMethod()
gets empty list
.
Result:
Now I have monstrous solution :(
public void Execute()
{
Console.WriteLine("Start main thread..");
List<int> listResponse = new List<int>();
int count = 0;
for (int i = 0; i < 5; i++)
{
var task = Task<int>.Factory.StartNew(() => webService.GetResponse(1))
.ContinueWith(x =>
{
Console.WriteLine("Start Callback..");
listResponse.Add(x.Result);
Console.WriteLine("End Callback");
count++;
if (count == 5)
{
webService.SomeMethod(listResponse);
}
});
}
Console.WriteLine("End main thread..");
Console.ReadLine();
}
Result:
That's what I need to wait for the asynchronous call. How can I use Wait
for Task
here?
UPDATE 2:
class Master
{
private readonly WebService webService = new WebService();
public delegate int GetResponseDelegate(int i);
public void Execute()
{
Console.WriteLine("Start main thread..");
GetResponseDelegate act = webService.GetResponse;
List<int> listRequests = new List<int>();
for (int i = 0; i < 5; i++)
{
act.BeginInvoke(1, (result =>
{
int req = act.EndInvoke(result);
listRequests.Add(req);
}), null);
}
webService.SomeMethod(listRequests);
Console.WriteLine("End main thread..");
Console.ReadLine();
}
}
I assume that is what you want. We are starting tasks and then waiting them to complete, after all are completed, we are getting results.
class Program
{
static void Main(string[] args)
{
Master master = new Master();
master.Execute();
}
}
class WebService
{
public int GetResponse(int i)
{
Random rand = new Random();
i = i + rand.Next();
Console.WriteLine("Start GetResponse()");
Thread.Sleep(3000);
Console.WriteLine("End GetResponse()");
return i;
}
public void SomeMethod(List<int> list)
{
//Some work with list
Console.WriteLine("List.Count = {0}", list.Count);
}
}
class Master
{
private readonly WebService webService = new WebService();
public void Execute()
{
Console.WriteLine("Start main thread..");
var taskList = new List<Task<int>>();
for (int i = 0; i < 5; i++)
{
Task<int> task = Task.Factory.StartNew(() => webService.GetResponse(1));
taskList.Add(task);
}
Task<List<int>> continueWhenAll =
Task.Factory.ContinueWhenAll(taskList.ToArray(),
tasks => tasks.Select(task => task.Result).ToList());
webService.SomeMethod(continueWhenAll.Result);
Console.WriteLine("End main thread..");
Console.ReadLine();
}
}
Ugly solution with BeginIvoke/EndInvoke
public void Execute()
{
Func<int, int> func = webService.GetResponce;
var countdownEvent = new CountdownEvent(5);
var res = new List<int>();
for (int i = 0; i < 5; ++i)
{
func.BeginInvoke(1, ar =>
{
var asyncDelegate = (Func<int, int>)((AsyncResult)ar).AsyncDelegate;
int ii = asyncDelegate.EndInvoke(ar);
res.Add(ii);
((CountdownEvent)((AsyncResult)ar).AsyncState).Signal();
}, countdownEvent);
}
countdownEvent.Wait();
Console.WriteLine(res.Count);
}