【问题标题】:How to Execute List of Tasks?如何执行任务列表?
【发布时间】:2016-08-16 17:36:02
【问题描述】:

我有一个List<System.Security.Claim> 列表,我想异步添加每个声明。我很好奇如何运行所有任务并设置boolean 以供以后使用以确保所有任务都已运行。

foreach (var claim in claims)
{
    claimTasks.Add(UserManager.AddClaimAsync(user.Id, claim));   
}

claimResultSucceeded = Task.WhenAll(claimTasks).IsCompleted;

我也试过这个:

foreach (var claim in claims)
{
    claimTasks.Add(Task.Run(() => UserManager.AddClaimAsync(user.Id, claim)));   
}

claimResultSucceeded = Task.WhenAll(claimTasks).IsCompleted;

编辑:如下图所示,任务处于故障状态:

{"第二个操作在前一个上下文之前开始 异步 操作完成。使用“等待”确保任何异步操作 在此上下文中调用另一个方法之前已完成。任何实例 成员不能保证是线程安全的。"}

【问题讨论】:

  • 您希望.IsCompleted 做什么?请说明您希望您的代码做什么以及您观察到它做什么。
  • @LasseV.Karlsen .IsCompleted 应该在所有任务都执行后包含 true 或 false 的结果。我用更多细节更新了问题。
  • @user1477388 不,它返回任务当前是否已完成,并立即返回。
  • @Servy,然后根据 Mike 在下面的回答,我如何检查所有任务是否已成功完成?
  • 基本上:await Task.WhenAll(claimTasks);.

标签: c# asp.net-mvc task


【解决方案1】:

你确定吗? Task.WhenAll 将采用一组 Task(因此接受来自这些任务的任何返回值)并返回一个您可能等待完成的新 Task,正如您所建议的那样?

我将下面的代码示例放在一起,基本上就是你展示的内容(加上一些无意义的数据,以确保有足够的编译)-

static async void Main(string[] args)
{
    // Declare some references to work with (this data is rubbish, it's just here so
    // that everything compiles)
    var userManager = new UserManager<User, Key>(null);
    var user = new User();
    var claims = new List<Claim>();
    var claimTasks = new List<Task<IdentityResult>>();

    // This is basically the code that appears in the question - it compiles fine
    foreach (var claim in claims)
    {
        claimTasks.Add(userManager.AddClaimAsync(user.Id, claim));
    }

    // WhenAll returns a single task that will be completed when all of the individual
    // claims tasks have completed
    var claimResults = await Task.WhenAll(claimTasks);

    // When this happens, you should be able to look at each of the IdentityResults
    // instances in the claimResults array to ensure they all succeeded
    // Note: I'm presuming a little here since I'm not too familiar with these types, but
    // it seems reasonable that the Succeeded flag on each IdentityResult should indicate
    // whether or not it was successfully retrieved
    var allRequestsSucceeded = claimResults.All(c => c.Succeeded);
}

// This struct and class have no purpose other than making the code compile
public struct Key : IEquatable<Key>
{
    public bool Equals(Key other) { throw new NotImplementedException(); }
}

public class User : IUser<Key>
{
    public Key Id
    {
        get { throw new NotImplementedException(); }
    }

    public string UserName
    {
        get {  throw new NotImplementedException(); }
        set { throw new NotImplementedException(); }
    }
}

【讨论】:

  • 正如你在我刚刚添加的照片中看到的那样,代码将编译并执行;但是,这些任务永远不会运行。它们一直处于故障状态,因为发生了错误(我之前没有意识到这一点)。
  • 啊,我明白了。您的问题最初说这是您遇到的返回类型问题 - IdentityResult 您想要一个布尔值,所以我假设您的代码没有编译。考虑到@Lasse V. Karlen 的评论,我将调整我的答案(为了后代),这是完全正确的(我不敢相信我最初没有注意到!)“IsCompleted”是检查错误的事情,应该等待WhenAll返回的任务。完成后,您的所有子任务都已完成(它们是成功还是失败可能是另一回事)。
【解决方案2】:

您的新错误来自实体框架。每个数据库上下文实例只能有一个异步操作。只需这样做:

foreach (var claim in claims)
{
    var result = await UserManager.AddClaimAsync(user.Id, claim);
    if (result.Succeded == false) {
        // Handle the error
    }
}

编辑: 纳入@Dan Roberts 建议。

【讨论】:

  • 有了这个,我如何检查所有任务是否已成功完成?
  • 如果您将其调整为“var addClaimResult = await UserManager.AddClaimAsync(user.Id, claim);”在循环中,您可以检查每个调用“addClaimResult.Succeeded”,并在其中任何一个说他们没有成功时设置一个标志。这种方法不会并行完成工作,但它将是异步的,因为在处理每个 AddClaimAsync 调用时线程不会被捆绑,这很有价值。我认为 Mike 可能比我更了解这些身份类别,而且这个答案可能比我的更好(所以它应该得到我的支持)。
  • 很好@DanRoberts,我编辑添加了检查结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-08
  • 1970-01-01
相关资源
最近更新 更多