C# 如何在C中正确执行异步任务列表#

C# 如何在C中正确执行异步任务列表#,c#,asynchronous,async-await,C#,Asynchronous,Async Await,我有一个需要在其上运行长时间运行的进程的对象列表,我希望异步启动它们,然后当它们全部完成时,将它们作为列表返回给调用方法。我一直在尝试我发现的不同方法,但是看起来这些进程仍然按照它们在列表中的顺序同步运行。因此,我确信,在如何执行任务列表的过程中,我遗漏了一些东西。 这是我的密码: public async Task<List<ShipmentOverview>> GetShipmentByStatus(ShipmentFilterModel filter) {

我有一个需要在其上运行长时间运行的进程的对象列表,我希望异步启动它们,然后当它们全部完成时,将它们作为列表返回给调用方法。我一直在尝试我发现的不同方法,但是看起来这些进程仍然按照它们在列表中的顺序同步运行。因此,我确信,在如何执行任务列表的过程中,我遗漏了一些东西。 这是我的密码:

public async Task<List<ShipmentOverview>> GetShipmentByStatus(ShipmentFilterModel filter)
    {
        if (string.IsNullOrEmpty(filter.Status))
        {
            throw new InvalidShipmentStatusException(filter.Status);
        }

        var lookups = GetLookups(false, Brownells.ConsolidatedShipping.Constants.ShipmentStatusType);

        var lookup = lookups.SingleOrDefault(sd => sd.Name.ToLower() == filter.Status.ToLower());

        if (lookup != null)
        {
            filter.StatusId = lookup.Id;
            var shipments = Shipments.GetShipments(filter);

            var tasks = shipments.Select(async model => await GetOverview(model)).ToList();

            ShipmentOverview[] finishedTask = await Task.WhenAll(tasks);

            return finishedTask.ToList();

        }
        else
        {

            throw new InvalidShipmentStatusException(filter.Status);

        }
    }


        private async Task<ShipmentOverview> GetOverview(ShipmentModel model)
    {
        String version;
        var user = AuthContext.GetUserSecurityModel(Identity.Token, out version) as UserSecurityModel;

        var profile = AuthContext.GetProfileSecurityModel(user.Profiles.First());

        var overview = new ShipmentOverview
        {
            Id = model.Id,
            CanView = true,
            CanClose = profile.HasFeatureAction("Shipments", "Close", "POST"),
            CanClear = profile.HasFeatureAction("Shipments", "Clear", "POST"),
            CanEdit = profile.HasFeatureAction("Shipments", "Get", "PUT"),
            ShipmentNumber = model.ShipmentNumber.ToString(),
            ShipmentName = model.Name,
        };

        var parcels = Shipments.GetParcelsInShipment(model.Id);

        overview.NumberParcels = parcels.Count;

        var orders = parcels.Select(s => WareHouseClient.GetOrderNumberFromParcelId(s.ParcelNumber)).ToList();

        overview.NumberOrders = orders.Distinct().Count();



        //check validations
        var vals = Shipments.GetShipmentValidations(model.Id);

        if (model.ValidationTypeId == Constants.OrderValidationType)
        {
            if (vals.Count > 0)
            {
                overview.NumberOrdersTotal = vals.Count();

                overview.NumberParcelsTotal = vals.Sum(s => WareHouseClient.GetParcelsPerOrder(s.ValidateReference));
            }
        }


        return overview;
    }
公共异步任务GetShipmentByStatus(ShipmentFilterModel筛选器)
{
if(string.IsNullOrEmpty(filter.Status))
{
抛出新的InvalidShipmentStatusException(filter.Status);
}
var lookups=GetLookups(false,Brownells.ConsolidatedShipping.Constants.ShipmentStatusType);
var lookup=lookups.SingleOrDefault(sd=>sd.Name.ToLower()==filter.Status.ToLower());
if(查找!=null)
{
filter.StatusId=lookup.Id;
var装运=装运。获取装运(过滤器);
var tasks=shippings.Select(异步模型=>await-GetOverview(模型)).ToList();
ShipmentOverview[]finishedTask=等待任务;
返回finishedTask.ToList();
}
其他的
{
抛出新的InvalidShipmentStatusException(filter.Status);
}
}
专用异步任务GetOverview(ShipmentModel模型)
{
字符串版本;
var user=AuthContext.GetUserSecurityModel(Identity.Token,out版本)作为UserSecurityModel;
var profile=AuthContext.GetProfileSecurityModel(user.Profiles.First());
var overview=新发货概述
{
Id=model.Id,
CanView=true,
CanClose=profile.HasFeatureAction(“装运”、“关闭”、“发布”),
CanClear=profile.HasFeatureAction(“装运”、“清除”、“邮寄”),
CanEdit=profile.HasFeatureAction(“装运”、“获取”、“放置”),
ShipmentNumber=model.ShipmentNumber.ToString(),
ShipmentName=model.Name,
};
var parcels=装运。GetParcelInshipment(model.Id);
overview.NumberParcels=包裹。计数;
var orders=parcels.Select(s=>WareHouseClient.GetOrderNumberFromParcelId(s.ParcelNumber)).ToList();
overview.NumberOrders=orders.Distinct().Count();
//检查验证
var VAL=装运。GetShipmentValidations(model.Id);
if(model.ValidationTypeId==Constants.OrderValidationType)
{
如果(VAL.Count>0)
{
overview.NumberOrdersTotal=vals.Count();
overview.NumberParcelsTotal=vals.Sum(s=>WareHouseClient.GetParcelsPerOrder(s.ValidateReference));
}
}
退货概述;
}

将该方法标记为
async
不会自动神奇地使其并行执行。由于您根本没有使用
wait
,它实际上将完全同步执行,就像它不是
async
一样。您可能在某个地方读到过
async
使函数异步执行的内容,但这根本不是真的-算了吧。当您使用
wait
并实际构建所有代码来管理这些任务及其错误处理时,它所做的唯一一件事就是构建一个状态机来处理任务继续

如果您的代码主要是I/O绑定的,请使用异步API和
await
,以确保这些方法实际并行执行。如果它们受CPU限制,则
任务.Run
(或
并行.ForEach
)将最有效

另外,执行
.Select(异步模型=>等待GetOverview(模型)
也没有意义。它几乎等同于
.Select(模型=>GetOverview(模型)
。在任何情况下,由于该方法实际上不返回异步任务,因此它将在执行
选择
时执行,远远早于进入
任务。当所有


有鉴于此,即使是
GetShipmentByStatus
async
也是非常无用的-您只能使用
wait
来等待
任务。当所有的
都完成时,但由于所有任务都已在该点完成,它将简单地同步完成。

如果您的任务是CPU绑定的,而不是I/O绑定的,那么下面是patt我相信您正在寻找:

static void Main(string[] args) {
    Task firstStepTask = Task.Run(() => firstStep());
    Task secondStepTask = Task.Run(() => secondStep());
    //...
    Task finalStepTask = Task.Factory.ContinueWhenAll(
    new Task[] { step1Task, step2Task }, //more if more than two steps...
    (previousTasks) => finalStep());
    finalStepTask.Wait();
}

看起来您正在使用异步方法,而实际上您需要线程

调用
async
方法时,将控制返回调用方法,然后等待
wait
上的方法完成。您可以看到它是如何工作的。
基本上,async/await方法的唯一用途不是锁定UI,以便它保持响应

如果要并行启动多个进程,则需要使用以下命令:

using System.Threading.Tasks;

public void MainMethod() {
    // Parallel.ForEach will automagically run the "right" number of threads in parallel
    Parallel.ForEach(shipments, shipment => ProcessShipment(shipment));

    // do something when all shipments have been processed
}

public void ProcessShipment(Shipment shipment) { ... }

如果您发布了一条消息,这将非常有帮助。@Adam:不要忽略编译器警告。上面的代码将导致一条警告,编译器会明确告诉您,您的方法将同步运行,这正是您看到的。谢谢您的回复。我需要对我的方法进行哪些更改才能返回异步任务?@Adam,如我所说,要么在方法中使用异步API和
wait
,要么完全放弃
async
,使用
Parallel.ForEach
(或
Task.Run
)。“鉴于此,即使是GetShipmentByStatus的异步也毫无用处”-这就是我从结果中收集到的信息,因此我提出这个问题的原因以及如何解决它。TLDR:
async
关键字只标记了一种方法,允许您使用
wait
关键字。
wait
关键字允许程序在等待时做其他事情(技术上称为
yield
).我想我知道如何让我的代码以这种模式运行,我会尝试一下,让你知道它是如何产生的,谢谢你的回复