【发布时间】:2010-06-10 07:07:43
【问题描述】:
我在异步调用方法方面遇到了设计问题。
我想知道调用异步方法的最佳/好的模式,它调用另一个异步方法,它调用另一个异步方法:)
换句话说,我有使用异步方法创建的 WCF 服务引用,我想从另一个异步方法调用它们,该方法由其他异步方法调用。 所有这些都是为了非阻塞 GUI。
谢谢!
【问题讨论】:
标签: c# .net wcf asynchronous
我在异步调用方法方面遇到了设计问题。
我想知道调用异步方法的最佳/好的模式,它调用另一个异步方法,它调用另一个异步方法:)
换句话说,我有使用异步方法创建的 WCF 服务引用,我想从另一个异步方法调用它们,该方法由其他异步方法调用。 所有这些都是为了非阻塞 GUI。
谢谢!
【问题讨论】:
标签: c# .net wcf asynchronous
如果您的唯一目标是拥有一个非阻塞的 GUI,那么多个级别是不必要的。一旦您的顶级方法在后台运行,您的 GUI 就会被释放。使用多个级别确实会带来额外的复杂性。
可能有其他原因(性能)来异步调用较低级别的方法,但这取决于。以后需要等结果吗?
所以我认为这里没有“模式”。
【讨论】:
在诸如 MonoRail 或 MS MVC 之类的 MVC 框架中创建异步控制器时,最好有多个级别的一个示例。最终调用某些 IO 阻塞的东西,例如来自 System.Data.SqlClient 或某个套接字的 SqlCommand,会将 IO 操作数放在 IO 完成端口上:http://msdn.microsoft.com/library/aa365198,这将保存托管/非托管线程的量用于某些东西更有用。
如果您编写返回 IAsyncResult 的类,那么您离实现协程不远了。这是一篇关于如何将异步编程与协程一起使用的好文章:http://blogs.msdn.com/b/pfxteam/archive/2009/06/30/9809774.aspx。
Caliburn,一个 WPF 框架,原生支持协程。与 .Net 4 一起发布的任务并行库为其任务提供了 IAsyncResult 接口。 [如果您是 3.5,那么您可能需要创建自己的实现(它们制作起来非常简单,只需实现接口)。] 协程是一种使用 IEnumerable 的编译器重写来将 IAsyncResults 推送到一堆要做的事情(从“异步管理器”中看到)。
F# async(如在否决的答案中所见)使用 monad(与它们在 CLR 上一样的 monadic)将异步请求的状态从 Begin* 移动到 End* 方法。编译器都将其转换为嵌套的 lambda 表达式/SelectMany。
【讨论】:
我最近开发了调用后端 Web 服务以检索数据的 ADFS 属性存储实现。我想遵循工厂 -> 客户端方法,而不是为每个调用重用客户端,所以我最终进行了 2 级异步调用,如下面的简化代码示例所示:
public class IMyAttributeStore : IAttributeStore
{
ChannelFactory<IMyBackendInterface> factory;
public IMyAttributeStore()
{
}
public IAsyncResult BeginExecuteQuery(string query, string[] parameters, AsyncCallback callback, object state)
{
AsyncResult queryResult = new TypedAsyncResult<string[][]>(callback, state);
var client = factory.CreateChannel();
CallState cs = new CallState(client, queryResult);
Request rq = new Request();
client.BeginGetUserRoles(rq, new AsyncCallback(AsyncCallCallback), cs);
return cs.result;
}
public string[][] EndExecuteQuery(IAsyncResult result)
{
return TypedAsyncResult<string[][]>.End(result);
}
// Initialize state here.
public void Initialize(Dictionary<string, string> config)
{
var endpoint = config["endpointConfigurationName"];
factory = new ChannelFactory<IMyBackendInterface>(endpoint);
}
void AsyncCallCallback(IAsyncResult result)
{
CallState cs = (CallState)result.AsyncState;
Response data = cs.client.EndGetUserRoles(result);
List<string[]> claimData = new List<string[]>();
foreach (var val in data.Values)
claimData.Add(new string[1] { val });
string[][] retVal = claimData.ToArray();
TypedAsyncResult<string[][]> queryResult = (TypedAsyncResult<string[][]>)cs.result;
queryResult.Complete(retVal, false);
}
}
class CallState
{
public IMyBackendInterface client;
public AsyncResult result;
public CallState(IMyBackendInterface c, AsyncResult r)
{
client = c;
result = r;
}
}
想知道这是一个可以遵循的好模式,还是有人同时发现了更好的模式?
【讨论】: