Reputation: 55
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
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
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 ID
s 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