考虑以下代码:
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();
}
}
我们有结果:
Start main thread..
End main thread
Start Method()..
End Method()
Start Callback..
End Callback
所以,我想要结果:
Start main thread..
Start Method()..
End Method()
Start Callback..
End Callback
End main thread
我如何在此代码中等待async
?我检查了MSDN文章"Calling Synchronous Methods Asynchronously",发现了这个:
致电BeginInvoke
后,您可以执行以下操作:
EndInvoke
阻止直到通话
完成。WaitHandle
获取IAsyncResultAsyncWaitHandle
属性,使用其WaitOne
方法阻止执行,直到执行
发出WaitHandle
信号,然后拨打EndInvoke
。IAsyncResult
返回的BeginInvoke
以确定何时
异步调用已完成,然后调用EndInvoke
。BeginInvoke
。方法
异步调用时在ThreadPool
线程上执行
完成。回调方法调用EndInvoke
。我认为这对我来说更好。但是如何实现呢?特别是我对重载WaitOne()
(Blocks the current thread until the current WaitHandle receives a signal)感兴趣。怎么做得对?我的意思是这种情况下的常见模式。
更新
现在我使用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();
}
}
主要问题是SomeMethod()
为空list
。
结果:
现在我有了可怕的解决方案:(
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();
}
结果:
这就是我需要等待异步调用。如何在此Wait
使用Task
?
更新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();
}
}
答案 0 :(得分:1)
从示例代码中不清楚为什么需要异步调用。如果不这样做,您可以同步拨打test.Method();
。
假设您需要异步执行,请不要使用过时的Delegate.BeginInvoke
内容。使用新的基于Task
的API:
var task = Task.Factory.StartNew(() => test.Method());
然后,您可以Wait
执行该任务或await
或使用Task.ContinueWith
(为您的案例选择合适的技巧)。
答案 1 :(得分:1)
我认为这就是你想要的。我们正在开始任务,然后等待他们完成,毕竟完成后,我们正在获得结果。
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();
}
}
使用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);
}