alireza
alireza

Reputation: 55

How get current object in operation parallel Thread

I am List of Object for send to api .i used parallel thread below.
code

  List<object> data  ;//contain data

                result =new  Dictionary<decimal, object>();
                

                var threadCount = 4;
                if (data.Count < threadCount)
                {
                    threadCount = data.Count;
                }

                var pageSize = threadCount > 0 ? Convert.ToInt32(Math.Ceiling((Convert.ToDecimal(data.Count) / threadCount))) : 0;
                var pageCount = threadCount;

                

                for (int j = 0; j < threadCount; j++)
                {

                    var temp = data.Skip(j * pageSize).Take(pageSize).ToList();
                    var tempLength = temp?.Count;
                    Parallel.ForEach(temp, item =>
                    {
                        result.Add(item.ID, null);

                       //call Api and get resultApi

                        if (resultApi != null && resultApi.Result != null)
                        {
                            
                            result[item.ID] = resultApi.Result.id;
                        }
                        else if (resultApi != null && resultApi .Message != null)
                        {
                            
                            result[item.ID] = null;
                        }
                        else
                        {
                            result[item.ID] = null;
                        }
                    });
                 }

problem
in end operation in top when check result i see some items are not related to their ID and have been moved.If there is no shift when I exit the parallel mode, all the identifiers are set correctly how resolve problem?

Upvotes: 1

Views: 164

Answers (2)

alireza
alireza

Reputation: 55

I have reached an answer. Which is as follows.
Code

List<object> data  ;//contain data

                result =new  Dictionary<decimal, object>();
                

                var threadCount = 4;
                if (data.Count < threadCount)
                {
                    threadCount = data.Count;
                }

                var pageSize = threadCount > 0 ? Convert.ToInt32(Math.Ceiling((Convert.ToDecimal(data.Count) / threadCount))) : 0;
                var pageCount = threadCount;

                

                for (int j = 0; j < threadCount; j++)
                {

                    var temp = data.Skip(j * pageSize).Take(pageSize).ToList();
                    var tempLength = temp?.Count;
                    Parallel.ForEach(temp, item =>
                    {
                      lock (result)
                        {
                           var temp = callapi(item.ID);
                           result.Add(temp.Item1, temp.Item2);
                        }
                    });
                 }
     private (decimal, object) callapi(decimal id){
                        //call Api and get resultApi

                        if (resultApi != null && resultApi.Result != null)
                        {
                            
                            result[item.ID] = resultApi.Result.id;
                            return (id,result);
                        }
                        else if (resultApi != null && resultApi .Message != null)
                        {
                            
                            result[item.ID] = null;
                            return (id,result);
                        }
                        else
                        {
                            result[item.ID] = null;
                            return (id,result);
                        }
}

Upvotes: 0

Theodor Zoulias
Theodor Zoulias

Reputation: 43802

My suggestion is to use PLINQ instead of the Parallel class. It is a safer tool to use, for entry-level multithreading. The PLINQ is like LINQ, but it starts with .AsParallel(). It includes almost all of the familiar LINQ operators like Select, Where, Take, ToList etc.

Dictionary<decimal, object> dictionary = data
    .AsParallel()
    .WithDegreeOfParallelism(4)
    .Cast<Item>()
    .Select(item => (item.ID, CallAPI(item).Result))
    .Where(entry => entry.Result != null)
    .ToDictionary(entry => entry.ID, entry => (object)entry.Result.Message);

The CallAPI method is assumed to have this signature: Task<APIResult> CallAPI(Item item);

This PLINQ query will process your data with a concurrency level of 4. This means that 4 operations will be concurrently in flight, and when one item completes the next one will start automatically.

The IDs are expected to be unique, otherwise the ToDictionary operator will throw an exception.

This approach is suggested for its simplicity, not for its efficiency. The PLINQ is not really intended for processing I/O bound workloads, and will needlessly block ThreadPool threads while doing so. You can look here for more efficient ways to throttle asynchronous I/O bound operations.

Upvotes: 1

Related Questions