【问题标题】:Modify instance variable used by multiple Tasks修改多个任务使用的实例变量
【发布时间】:2014-06-11 04:02:17
【问题描述】:

我需要一些帮助来处理任务。我有一个反序列化为一个类的 XML 字符串。类本身包含一个属性,例如rssProvider 设置为唯一值,如 MSN 或 YAHOO。但是,在此字段中可以有多个用 , 分隔的值。

我在多个任务中使用这个反序列化的类实例。但是,在此任务中调用的函数只能使用一个 rssProvider 值,因此我对该字符串进行了拆分,并使用了一个创建任务的 foreach 循环。

在任务本身中,我调用的函数需要完整的对象,但只有一个 rssProvider。但是,当我将该属性的值更改为 foreach 中的值时,其他任务将失败,因为它们将从首先运行的任务中获得相同的单个值。

任何想法我应该如何重构逻辑?谢谢!

我的代码:

        List<Task<ResponseOBJ>> tasks = new List<Task<ResponseOBJ>>();
        // get List of rssProviders
        string[] providers = request.requestBody.rssProvider.Split(',');

        //go through each provider
        foreach (string provider in providers)
        {
            Task<ResponseOBJ> task = Task.Factory.StartNew<ResponseOBJ>(() =>
                {
                    request.requestBody.rssProvider = provider;
                    doStuff(request);
                }
            tasks.Add(task);
        }

        Task.WaitAll(tasks.ToArray());

【问题讨论】:

  • 这个问题太宽泛了......有成千上万的选项可以解决您的问题。最简单的一种,创建两个属性,AvailableProviders(包含所有值)和 CurrentProvider(当前正在使用的)。
  • 发布你的代码,我们看看能做什么
  • 问题是,如果我在任务中为该对象设置 CurrentProvider,它将立即被下一个最快的任务覆盖。
  • 如何为每个请求创建一个新的请求对象?
  • 使用 new 运算符然后分配请求并更改值是否就足够了,还是我需要分配每个属性?

标签: c# asynchronous foreach task


【解决方案1】:

我会在您的 Request 对象中创建一个复制构造函数,它复制原始 Request 的内容并创建一个新的:

public class Request
{
    public Request(Request oldRequest)
    {
          // initalize new request from the old
    }
}

然后更改我的代码为每个任务创建一个新请求:

 List<Task<ResponseOBJ>> tasks = new List<Task<ResponseOBJ>>();
    // get List of rssProviders
 string[] providers = request.requestBody.rssProvider.Split(',');

    //go through each provider
    foreach (string provider in providers)
    {
        Task<ResponseOBJ> task = Task.Factory.StartNew<ResponseOBJ>(() =>
            {
                request.requestBody.rssProvider = provider;
                var newRequest = new Request(request);               
                doStuff(newRequest);
            }
        tasks.Add(task);
    }

    Task.WaitAll(tasks.ToArray());    

【讨论】:

    【解决方案2】:

    一种选择可能是将doStuff(request) 更改为doStuff(request, provider) 并删除request.requestBody.rssProvider = provider; 行,然后相应地更改您的doStuff

        foreach (string provider in providers)
        {
            Task<ResponseOBJ> task = Task.Factory.StartNew<ResponseOBJ>(() =>
                {
                    doStuff(request, provider);
                }
            tasks.Add(task);
        }
    

    另一个选项(如上面的 cmets 中也提到的)是为每个提供者创建一个新的请求对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-15
      • 2017-07-11
      • 2016-12-19
      • 2014-07-15
      • 2023-03-08
      • 2020-10-31
      • 1970-01-01
      相关资源
      最近更新 更多