匿名异步,什么是正确的方法?

时间:2015-09-03 14:39:21

标签: c# asynchronous async-await

我有一个简单的类来做同步的事情,

    <telerik:GridTemplateColumn UniqueName="AccountCode" HeaderText="Account Code">
        <ItemTemplate>
             <asp:Label ID="lblAcCode" runat="server" Text='<%# Eval("AccountCode")%>'></asp:Label>
        </ItemTemplate>
        <EditItemTemplate>
             <asp:Label ID="lblAcCode2" runat="server" Text='<%# Eval("AccountCode") + " - " + Eval("AccountDescription")%>' Visible="false"></asp:Label>
             <telerik:RadComboBox ID="ddlAccountCode" runat="server" Height="200" Width="240" DropDownWidth="310" HighlightTemplatedItems="true" CausesValidation="true" 
OnItemsRequested="ddlAccountCode_ItemsRequested" EnableItemCaching="true" ShowDropDownOnTextboxClick="false" EnableLoadOnDemand="True" ShowMoreResultsBox="true" EnableVirtualScrolling="true" MarkFirstMatch="True" AllowCustomText="true"
Filter="Contains" AppendDataBoundItems="true" DataTextField="AccountDescription" DataValueField="AccountCodeID" AutoPostBack="true" OnSelectedIndexChanged="ddlAccountCode_SelectedIndexChanged">
             </telerik:RadComboBox>                            
             <telerik:RadButton id="btnSearch" runat="server" text="Search" OnClick="btnSearch_Click">
             </telerik:RadButton>
          </EditItemTemplate>
    </telerik:GridTemplateColumn>

显然,这段代码没有完全定义,但确实说明了我的问题。

现在,类RadComboBoxpublic static class Synchronous { public static void DoTheWholeThing() { AStuff aStuff; using (var a = new A()) { aStuff = a.GetStuff(); } BStuff bStuff; using (var b = new B()) { bStuff = b.GetStuff(); } var combination = CombineStuff(aStuff, bStuff); } private static Combination CombineStuff(AStuff aStuff, BStuff bStuff) { //// Magic Here } } 都负责从不同的远程源检索数据。因此,AB的开发人员已经实现了名为A的异步入口点,它们分别返回BGetStuffAsync

我想最大限度地利用异步方法并同时调用它们,这样我就可以减少代码的整体等待时间。

到目前为止,这是我编造的内容。

Task<AStuff>

除了这个代码好奇地看起来像javascript模块模式,这是正确的方法。我不认为我应该使用Task.Run,因为此代码为clearly not CPU bound

似乎有点&#34;笨拙&#34;我需要实例化类型代理来执行此操作。还有更好的方法吗?

修改

以下两个好的答案我在命名函数和延续之间陷入困境。

3 个答案:

答案 0 :(得分:3)

当您简单地将匿名方法提取到命名方法时,代码变得非常简单:

public async static Task DoTheWholeThing(CancellationToken cancellationToken)
{
    var getAStuffTask = GetAStuffAsync(cancellationToken);
    var getBStuffTask = GetBStuffAsync(cancellationToken);

    var combination = CombineStuff(
        await getAStuffTask,
        await getBStuffTask);
}

private static async Task<AStuff> GetAStuffAsync(CancellationToken cancellationToken)
{
    using (var a = new A())
    {
        return await a.GetStuffAsync(cancellationToken);
    }
}
private static async Task<BStuff> GetBStuffAsync(CancellationToken cancellationToken)
{
    using (var b = new B())
    {
        return await b.GetStuffAsync(cancellationToken);
    }
}

那就是说,如果真的想要坚持使用匿名方法,你可以创建一个帮助方法,允许泛型类型推断和lambdas隐式地找出委托的类型:

public async static Task DoTheWholeThing(CancellationToken cancellationToken)
{
    var getAStuffTask = Start(async () =>
            {
                using (var a = new A())
                {
                    return await a.GetStuffAsync(cancellationToken);
                }
            });

    var getBStuffTask = Start(async () =>
            {
                using (var b = new B())
                {
                    return await b.GetStuffAsync(cancellationToken);
                }
            });

    var combination = CombineStuff(
        await getAStuffTask,
        await getBStuffTask);
}
public static Task<T> Start<T>(Func<Task<T>> asyncOperation)
{
    return asyncOperation();
}

答案 1 :(得分:3)

一旦任务完成,请使用TPL延续来调用Dispose

public async static Task DoTheWholeThing(CancellationToken cancellationToken)
{
    var a = new A();
    var b = new B();

    // start the tasks and store them for awaiting later
    var getAStuffTask = a.GetStuffAsync(cancellationToken);
    var getBStuffTask = b.GetStuffAsync(cancellationToken);

    // queue up continuations to dispose of the resource as soon as it is not needed
    getAStuffTask.ContinueWith(() => a.Dispose());
    getBStuffTask.ContinueWith(() => b.Dispose());

    // await as normal
    var combination = CombineStuff(
        await getAStuffTask,
        await getBStuffTask);
}

我不确定将整个方法包装在附加using块中是否可以完成任何操作,但它可以让您高枕无忧。

答案 2 :(得分:1)

您不需要在代理中包装异步调用以使它们立即执行。如果直接调用$(function() { $('.component-individual-detail-profile').each(function() { var $self = $(this), $images = $self.find('.photos'); $images.find('li').click(function(e) { e.preventDefault(); var thumb = $(this); $images.find('.selected') .attr('src', thumb.find('img').attr('src')) .attr('alt', thumb.find('img').attr('alt')) .attr('title', thumb.find('img').attr('title')); }); }); }); 方法而不等待它们,则会得到相同的结果。

GetStuffAsync

请注意,这会在调用public static class Asynchronous { public async static Task DoTheWholeThing(CancellationToken cancellationToken) { using (var a = new A()) using (var b = new B()) { var taskA = a.GetStuffAsync(cancellationToken); var taskB = b.GetStuffAsync(cancellationToken); await Task.WhenAll(new [] { taskA, taskB }); var combination = CombineStuff(taskA.Result, taskB.Result); } } private Combination CombineStuff(AStuff aStuff, BStuff bStuff) { //// Magic Here } } 期间将ab对象保持为@Servy备注。如果这是一个问题,CombineStuff对象的声明可以移到Task块之外,如下所示:

using

虽然只要两个任务都在运行,这仍然适用于public static class Asynchronous { public async static Task DoTheWholeThing(CancellationToken cancellationToken) { Task taskA; Task taskB; using (var a = new A()) using (var b = new B()) { taskA = a.GetStuffAsync(cancellationToken); taskB = b.GetStuffAsync(cancellationToken); await Task.WhenAll(new [] { taskA, taskB }); } var combination = CombineStuff(taskA.Result, taskB.Result); } private Combination CombineStuff(AStuff aStuff, BStuff bStuff) { //// Magic Here } } a,而不是在它们返回时处理每个任务。