简体   繁体   English

如何在C#中为多个值运行单个进程?

[英]How to run single process for multiple values in c#?

I need to run single process for list of symbols. 我需要为符号列表运行单个过程。 So I have a list of symbols like AAPL, FB, QQQ, MSFT, IBM and also I have a function which contains logic of calculations for given symbol. 因此,我有一个符号列表,如AAPL,FB,QQQ,MSFT,IBM,而且我还有一个函数,其中包含给定符号的计算逻辑。 So perform my this logic I am using Task. 因此,请执行我使用Task的逻辑。

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);

So when I am running this code then it's showing me error like 所以当我运行这段代码时,它向我显示错误

Index was out of range. 索引超出范围。 Must be non-negative and less than the size of the collection. 必须为非负数并且小于集合的大小。

Error is showing on line: 错误显示在网上:

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

where I am going to pass symbol name to the function. 我将在其中将符号名称传递给函数。

So please can I get a solution for this? 因此,我可以为此解决方案吗? I have checked on google for this it's saying for the index is out of range. 我已经在google上检查过,这是因为索引超出范围。 I have checked by set debugger but I not understand how to check it for task regions. 我已经通过设置调试器进行了检查,但是我不明白如何检查任务区域。

Parallel.Foreach can do this. Parallel.Foreach可以做到这一点。 Here an example how to: 这里有一个示例如何:

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));
}

You can control the call by using ParallelOptions : 您可以使用ParallelOptions控制呼叫:

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

First, I would use the concurrent collection ConcurrentBag in this case(if you write into the collection). 首先,在这种情况下(如果您写入集合),我将使用并发集合ConcurrentBag Concurrent collections are going to lock the instance when multiple threads are about to access it. 当多个线程将要访问实例时,并发集合将锁定该实例。 Also, I would suggest using Task.WhenAll with await keyword. 另外,我建议将Task.WhenAllawait关键字一起使用。 Task.WaitAll can create a deadlock. Task.WaitAll可以创建死锁。 So here is a sample you can try out: 因此,您可以尝试以下示例:

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);
}

Probably you should replace: 可能您应该替换:

symbolList.IndexOf(i)

...with: ...有:

symbolList[i]

Apart from the fact that you've got illegal code ( symbolList.IndexOf(i) should probably be symbolList[i] ) the issue you're facing is that you're not capturing the loop variable before you call the lambda. 除了您有非法代码( symbolList.IndexOf(i)应该是symbolList[i] )的事实之外,您面临的问题是在调用lambda之前没有捕获循环变量。

Here's the simple fix: 这是简单的解决方法:

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);

Note the line string symbol = symbolList[i]; 注意,行string symbol = symbolList[i]; before you start the task. 在开始任务之前。

If you don't do this the loop finishes before the tasks start and then i is equal to taskArray.Length and hence you get the "Index was out of range" error. 如果不这样做,循环将在任务开始之前完成,然后i等于taskArray.Length ,因此会出现“索引超出范围”错误。

The other this I'd suggest is you should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive and add using System.Reactive.Linq; 我建议的另一个建议是,您应该使用Microsoft的Reactive Framework(aka Rx)-NuGet System.Reactiveusing System.Reactive.Linq;添加using System.Reactive.Linq; - then you can do this: -那么您可以执行以下操作:

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();

Much simpler and cleaner than tasks. 比任务简单,干净得多。 Then you can use LINQ operators on the results too. 然后,您也可以对结果使用LINQ运算符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM