0

I am trying to improve the speed of execution of a program. I use the task to make it run concurrently. The following is my original code:

StringBuilder expression = new StringBuilder(1024);
int count = table.Rows.Count;
for (int i = 0; i < count; i++)
{                   
    string result = GetResult(companyID);                            
    expression.Append(result);
}   

And I change to something like this:

StringBuilder expression = new StringBuilder(1024);
int count = table.Rows.Count;
for (int i = 0; i < count; i++)
{
   try
    {
        Task task1 = Task.Factory.StartNew(() =>
        {
            string result = GetResult(companyID);                                                        
            expression.Append(result);
        });
    }
    catch (Exception ex) {
    }
} 

However, the result is not the same. How can I make the result same with the use of task?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
want_to_be_calm
  • 1,477
  • 3
  • 23
  • 41
  • What do you expect and what you get? – Backs Apr 04 '18 at 01:38
  • So now your `append` will no longer be sequential? if `getresult` is what is causing you grief, look into either `DataFlow` or simply putting results into a `ConcurrentQueue` and then appending together. – zaitsman Apr 04 '18 at 01:41
  • Tasks are not guaranteed to finish in the order they are created, so if you're appending everything to the same `StringBuilder`, the content is likely to end up out of order, if it even works at all-- [`StringBuilder`](https://stackoverflow.com/questions/8831385/is-nets-stringbuilder-thread-safe) is not thread-safe. – John Wu Apr 04 '18 at 01:41
  • OP, is your code example accurate? It seems you are callng `GetResult()` with the same argument, over and over. Where is CompanyID declared and how is it populated? – John Wu Apr 04 '18 at 01:45
  • What is `GetResult(companyID)` what is it returning, why is `companyID` always the same, and do you mind the results in any particular order. also `stringbuilder` is not thread safe at all, who knows what the internal buffers will do – TheGeneral Apr 04 '18 at 01:50
  • I have omitted the code changing CompanyID. Actually, the companyID will be changed accordingly. – want_to_be_calm Apr 04 '18 at 01:53
  • Is GetResult IO bound work i.e from a file network or db, and do you care if the result are in order – TheGeneral Apr 04 '18 at 01:55
  • Something like `String.Concat(Enumerable.Range(0,count).AsParallel().Select(i=>new {result=GetResult(companyID),idx=i}).OrderBy(x=>x.idx).Select(x=>x.result))` might work for you, assuming `GetResult` is thread-safe. It probably isn't (and looks like it might have side-effects). Your question needs more info. – spender Apr 04 '18 at 01:56

1 Answers1

0

Simplifying your situation:

List<string> Outputs = new List<string>();

for(int i=0; i< 100; i++)
{
    Outputs.Add($"Hello World: {i}");
}

Here, Output is a List of strings with Hello World: 1, 2, ....:

enter image description here

Your way of Parallelizing this - will not guarantee the same order (because thats what parallelization is, you cant say which task completes first).

If you are expecting the same output as with sequential logic, but want to do it parallely, you can do something like:

Parallel.For(0, 100, (i) =>
{
    Outputs.Insert(i, $"Hello World: {i}");
});

Notice, code in the loop body - Inserts strings at the expected index. Which will create the expected output.

Prateek Shrivastava
  • 1,877
  • 1
  • 10
  • 17
  • Thanks, Prateek, What can I do If I want to append something inside the loop. like Outputs.append(i, "abc"), Outputs.append(i, "cde"). That means more than one operation of the Outputs. Can I do that? – want_to_be_calm Apr 09 '18 at 06:15
  • @want_to_be_calm - List does not have Append. I guess you are thinking in terms of using StringBuilder - which is more or less like a String.Append. You cannot guarantee where the append would happen.. – Prateek Shrivastava Apr 10 '18 at 02:06