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
).我想我知道如何让我的代码以这种模式运行,我会尝试一下,让你知道它是如何产生的,谢谢你的回复