【问题标题】:How to run single process for multiple values in c#?如何在 C# 中为多个值运行单个进程?
【发布时间】:2019-04-11 09:33:39
【问题描述】:

我需要为符号列表运行单个进程。所以我有一个符号列表,如 AAPL、FB、QQQ、MSFT、IBM,还有一个函数,其中包含给定符号的计算逻辑。所以执行我正在使用任务的这个逻辑。

List<string> symbolList = new List<string>() {"AAPL","QQQ","FB","MSFT","IBM"};
Task[] taskArray = new Task[symbolList.Count];
for(int i=0; i<taskArray.Length; i++)
{
   taskArray[i] = Task.Factory.StartNew(() =>
       {
          criteriaEvalution.Evaluate(finalArray, false, new List<parseObj>(), ref builder, symbolList.IndexOf(i));
       });
}
Task.WaitAll(taskArray);

因此,当我运行此代码时,它会向我显示类似

的错误

索引超出范围。必须为非负数且小于集合的大小。

在线显示错误:

criteriaEvalution.Evaluate(finalArray, false, new List<parseObj>(), ref builder, symbolList.IndexOf(i));

我要将符号名称传递给函数的位置。

请问我可以为此找到解决方案吗? 我已经在谷歌上检查过它说索引超出范围。我已经通过设置调试器进行了检查,但我不明白如何检查任务区域。

【问题讨论】:

  • symbolList.IndexOf(i) 将始终返回 -1(我不知道您如何编写此代码而不会出现任何来自 IDE 的错误),它应该是您存储在列表中的某些内容的索引,例如symbolList.IndexOf("AAPL") 这将返回 0 和 symbolList.IndexOf("QQQ") 这将返回 1
  • 如果我使用 symbolList[i] 那么它也会显示同样的错误。
  • 我可以看到标准评估类的完整代码吗?

标签: c# multithreading linq parallel-processing task


【解决方案1】:

Parallel.Foreach 可以做到这一点。这里有一个例子:

public static void DoIt(string a)
{
    Console.WriteLine(a);
}

public static void Main(string[] args)
{
    List<string> symbolList = new List<string>() { "AAPL", "QQQ", "FB", "MSFT", "IBM" };
    Parallel.ForEach(symbolList, a => DoIt(a));
}

您可以使用ParallelOptions控制通话:

ParallelOptions options = new ParallelOptions() { MaxDegreeOfParallelism = 10 };
Parallel.ForEach(symbolList, options, a => DoIt(a));

【讨论】:

  • 更糟糕的是,Parallel lib 占用大量CPU,不建议用于服务器端代码
  • 我需要在服务器端处理这个过程。列表中也会有多个符号。
  • @OlegI 将 parallel.foreach 消耗大量 cpu 使用?
  • @Ankit 是的,例如不推荐用于网络应用程序。当有很多并发用户时
  • 所以在这种情况下我需要使用哪种方法来处理并发进程。你能推荐我吗?
【解决方案2】:

首先,在这种情况下,我将使用并发集合ConcurrentBag(如果您写入集合)。当多个线程将要访问它时,并发集合将锁定该实例。另外,我建议使用 Task.WhenAllawait 关键字。 Task.WaitAll 会造成死锁。因此,您可以尝试以下示例:

public static async Task Main()
{
    var symbolList = new ConcurrentBag<string> { "AAPL", "QQQ", "FB", "MSFT", "IBM" };
    var taskArray = new List<Task>();

    foreach (var s in symbolList)
    {
        var task = Task.Run(() =>
        {
            Process(s);
        });

        taskArray.Add(task);
    }

    await Task.WhenAll(taskArray);
}

【讨论】:

  • ConcurrentBag 是一个非常专业的容器。在某些情况下,使用ConcurrentQueueConcurrentStack 可以获得更好的性能,并且在枚举集合时排序会更直观。
  • 这不会解决它 - 你没有在 lambda 中捕获 s
  • @Enigmativity 实际上是 it does,来自 C# 版本 5 及更高版本。 :-)
  • @TheodorZoulias - 它很好地解释了 OP 的问题。也许他使用的是旧版本的框架?
  • 感觉我们不再试图解决他真正的问题了。问题是,发布的代码还有其他问题,因此发布了不同的答案
【解决方案3】:

也许你应该替换:

symbolList.IndexOf(i)

...与:

symbolList[i]

【讨论】:

    【解决方案4】:

    除了你有非法代码(symbolList.IndexOf(i) 应该是symbolList[i])之外,你面临的问题是你在调用 lambda 之前没有捕获循环变量。

    这是简单的解决方法:

    List<string> symbolList = new List<string>() { "AAPL", "QQQ", "FB", "MSFT", "IBM" };
    Task[] taskArray = new Task[symbolList.Count];
    for (int i = 0; i < taskArray.Length; i++)
    {
        string symbol = symbolList[i];
        taskArray[i] = Task.Factory.StartNew(() =>
        {
            criteriaEvalution.Evaluate(finalArray, false, new List<parseObj>(), ref builder, symbol);
        });
    }
    Task.WaitAll(taskArray);
    

    在开始任务之前注意string symbol = symbolList[i];这一行。

    如果您不这样做,则循环在任务开始之前完成,然后i 等于taskArray.Length,因此您会收到“索引超出范围”错误。

    我建议的另一个是你应该使用微软的反应框架(又名 Rx) - NuGet System.Reactive 并添加 using System.Reactive.Linq; - 然后你可以这样做:

    List<string> symbolList = new List<string>() { "AAPL", "QQQ", "FB", "MSFT", "IBM" };
    
    var query =
        from symbol in symbolList.ToObservable()
        from e in Observable.Start(() =>
            criteriaEvalution.Evaluate(finalArray, false, new List<parseObj>(), ref builder, symbol))
        select e;
    
    query.ToArray().Wait();
    

    比任务更简单、更干净。然后你也可以对结果使用 LINQ 运算符。

    【讨论】:

    • 我不认为在你的项目中安装一个巨大的依赖来解决这个简单的情况是一个好主意。
    • @OlegI - 为什么巨大依赖?我同意这是一个依赖,但很大?
    • 对我来说,这似乎有点矫枉过正,因为可以通过更简单的方式解决它,而无需添加外部依赖项。但无论如何感谢您的回答,很高兴看到其他选项。可以帮助读者
    猜你喜欢
    • 2018-09-14
    • 2014-07-05
    • 2016-10-11
    • 2016-06-22
    • 2013-06-28
    • 1970-01-01
    • 2019-01-26
    • 1970-01-01
    • 2018-02-03
    相关资源
    最近更新 更多