异步 WCF 查询最后一步
我正在尝试学习如何实现异步模式来同时查询多个 wcf 服务,但不知道如何检查所有并发调用是否已完成。我有一个执行异步操作的类,然后在操作完成时添加到列表中:
public static class ODataAsync
{
static DataServiceContext ServiceContext;
static List<DynamicEntity> Results = new List<DynamicEntity>();
private static void GetAsync(string serviceUri, NameValueCollection queryOptions, IAuthenticationScheme authenticationScheme)
{
string baseUri;
string entitySet;
string entityKey;
string queryString;
ValidateServiceUri(serviceUri, out baseUri, out entitySet, out entityKey, out queryString);
string resource = !string.IsNullOrEmpty(entityKey) ? entitySet + "(" + entityKey + ")" : entitySet;
DataServiceContext context = new DataServiceContext(new Uri(baseUri));
context.IgnoreMissingProperties = true;
ServiceContext = context;
DataServiceContextHandler handler = new DataServiceContextHandler(authenticationScheme);
handler.HandleGet(context);
DataServiceQuery<EntryProxyObject> query = context.CreateQuery<EntryProxyObject>(resource);
NameValueCollection options = HttpUtility.ParseQueryString(queryString);
options.Add(queryOptions);
foreach (string key in options.AllKeys)
{
query = query.AddQueryOption(key, options[key]);
}
try
{
query.BeginExecute(GetAsyncComplete, query);
}
catch (DataServiceQueryException ex)
{
throw new ApplicationException("An error occurred during query execution.", ex);
}
}
private static void GetAsyncComplete(IAsyncResult result)
{
QueryOperationResponse<EntryProxyObject> response =
((DataServiceQuery<EntryProxyObject>)result).EndExecute(result) as QueryOperationResponse<EntryProxyObject>;
IList<dynamic> list = new List<dynamic>();
foreach (EntryProxyObject proxy in response)
{
DynamicEntity entity = new DynamicEntity(proxy.Properties);
Results.Add(entity);
}
while (response.GetContinuation() != null)
{
Uri uri = response.GetContinuation().NextLinkUri;
response = ServiceContext.Execute<EntryProxyObject>(uri) as QueryOperationResponse<EntryProxyObject>;
foreach (EntryProxyObject proxy in response)
{
DynamicEntity entity = new DynamicEntity(proxy.Properties);
Results.Add(entity);
}
}
}
}
我的两个问题是:
1)如何确保仅在所有并发调用完成时才获得列表结果?例如,如果在循环中调用 GetAsync(),启动多个并发进程,我需要确保它们全部完成,然后再从列表结果中取出数据。
2) 我可以在 GetContinuation() 调用中使用 BeginExecute() 并递归地使用相同的方法 GetAsyncComplete() 作为回调函数吗?或者这会创建大量线程并实际上减慢速度。
谢谢。
I am trying to learn how to implement an asynchronous pattern to query multiple wcf services concurrently, but do not know how to check that all concurrent calls are complete. I have a class that executes the asynchronous operations and then adds to a List as operations complete:
public static class ODataAsync
{
static DataServiceContext ServiceContext;
static List<DynamicEntity> Results = new List<DynamicEntity>();
private static void GetAsync(string serviceUri, NameValueCollection queryOptions, IAuthenticationScheme authenticationScheme)
{
string baseUri;
string entitySet;
string entityKey;
string queryString;
ValidateServiceUri(serviceUri, out baseUri, out entitySet, out entityKey, out queryString);
string resource = !string.IsNullOrEmpty(entityKey) ? entitySet + "(" + entityKey + ")" : entitySet;
DataServiceContext context = new DataServiceContext(new Uri(baseUri));
context.IgnoreMissingProperties = true;
ServiceContext = context;
DataServiceContextHandler handler = new DataServiceContextHandler(authenticationScheme);
handler.HandleGet(context);
DataServiceQuery<EntryProxyObject> query = context.CreateQuery<EntryProxyObject>(resource);
NameValueCollection options = HttpUtility.ParseQueryString(queryString);
options.Add(queryOptions);
foreach (string key in options.AllKeys)
{
query = query.AddQueryOption(key, options[key]);
}
try
{
query.BeginExecute(GetAsyncComplete, query);
}
catch (DataServiceQueryException ex)
{
throw new ApplicationException("An error occurred during query execution.", ex);
}
}
private static void GetAsyncComplete(IAsyncResult result)
{
QueryOperationResponse<EntryProxyObject> response =
((DataServiceQuery<EntryProxyObject>)result).EndExecute(result) as QueryOperationResponse<EntryProxyObject>;
IList<dynamic> list = new List<dynamic>();
foreach (EntryProxyObject proxy in response)
{
DynamicEntity entity = new DynamicEntity(proxy.Properties);
Results.Add(entity);
}
while (response.GetContinuation() != null)
{
Uri uri = response.GetContinuation().NextLinkUri;
response = ServiceContext.Execute<EntryProxyObject>(uri) as QueryOperationResponse<EntryProxyObject>;
foreach (EntryProxyObject proxy in response)
{
DynamicEntity entity = new DynamicEntity(proxy.Properties);
Results.Add(entity);
}
}
}
}
My 2 questions are:
1) How do I ensure that I only get the List Result(s) when all concurrent calls are finished? For instance if call GetAsync() within a loop, starting several concurrent processes, I need to ensure that they are all finished before taking the data out of the List Result.
2) Can I use BeginExecute() inside the GetContinuation() call and recursively use the same method GetAsyncComplete() as the callback function ? Or would that create a ton of threads and actually slow things down.
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
看一下静态 WaitHandle.WaitAll(WaitHandle[] waitHandles)方法。该页面上有一个很棒的代码示例。
通常,任何实现异步模式的类都会定义以下形式的方法:
调用
BeginXXX
异步调用该方法,调用EndXXX
强制当前线程等待,直到异步方法完成。要进行多个异步调用,您只需根据需要多次调用
BeginXXX
,然后调用传入 IAsyncResult 的WaitHandle.WaitAll(...)
即可。 AsyncWaitHandle 用于您要等待的所有调用。要回答你的第二个问题,是的,你可以递归地使用
GetAsynComplete
。提供给BeginXXX
调用的state
参数用于识别请求,并且可以通过IAsyncResult.UserState
属性访问 - 因此您可以匹配请求到响应。这是否是一件好事有点主观。通常,异步调用通过线程池进行,因此一次创建大量异步调用可能会耗尽可用线程,之后新的调用将排队,直到有线程可用。在线程之间切换会产生一些开销,但与同步执行切换所需的时间相比,这可能不会很大(除非您有大量线程)。
Have a look at the static WaitHandle.WaitAll(WaitHandle[] waitHandles) method. There's a great code example on that page.
Typically, any class implementing the asynchronous pattern will define methods of the form:
Calling
BeginXXX
invokes the method asynchronously, and callingEndXXX
forces the current thread to wait until the asynchronous method completes.To make multiple asynchronous calls, all you need to do is call
BeginXXX
as many times as necessary, and then callWaitHandle.WaitAll(...)
passing in the IAsyncResult.AsyncWaitHandle for all of the calls that you want to wait for.To answer your second question, yes you can use
GetAsynComplete
recursively. Thestate
parameter given toBeginXXX
call is used to identify the request, and can be accessed via theIAsyncResult.UserState
property - so you can match a request to a response.Whether or not this is a good thing is a bit more subjective. Usually, async calls go via a threadpool, so creating lots of them at once can exhaust the available threads and after that, new calls get queued until a thread becomes available. There is some overhead in switching between threads, but that is probably not going to be significant (unless you have a very large number of threads), compared to the time taken to do it synchronously.