Reputation:
I have a list which contains 2 other lists and I am deciding in the loop where the items should go on the basis of type.
The for
loop was taking 10 min so I used Parallel.For
as I read somewhere it increases the performance. But now an exception is being thrown. Please let me know why.
my code
var treeQuery = new Microsoft.TeamFoundation.WorkItemTracking.Client.Query(_workitemstore, query);
var links = treeQuery.RunLinkQuery();
var workItemIds = links.Select(l => l.TargetId).ToArray();
query = "SELECT * FROM WorkItems";
var flatQuery = new Microsoft.TeamFoundation.WorkItemTracking.Client.Query(_workitemstore, query, workItemIds);
var workItemCollection = flatQuery.RunQuery();
var workItemList = new List<WorkItemViewModel>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
// for (int i = 0; i < workItemCollection.Count; i++)
Parallel.For(1, workItemCollection.Count, (i) =>
{
var workItem = workItemCollection[i];
if (workItem.Type.Name == "Product Backlog Item")
{
var model = new WorkItemViewModel()
{
FID = (workItem.WorkItemLinks.Count > 0) ? ((workItem.WorkItemLinks[0].LinkTypeEnd.Name.ToString() != "Child") ? workItem.WorkItemLinks[0].TargetId : 0) : 0,
ID = workItem.Id,
Name = workItem.Title,
State = workItem.State,
priorty = Convert.ToInt32(workItem.Fields["Priority"].Value),
// Size =(int) workItem.Fields["Size"].Value ,
Size = Convert.ToInt32(workItem.Fields["Effort"].Value),
StoryPoints = Convert.ToInt32(workItem.Fields["Story Points"].Value),
DoneStatus = workItem.Fields["Done Status"].Value.ToString(),
StoryOwner = workItem.Fields["Story Owner"].Value.ToString(),
Assignedto = workItem.Fields["Assigned To"].Value.ToString(),
StoryAuthor = workItem.Fields["Story Author"].Value.ToString(),
IterationPath = workItem.IterationPath
};
lock (workItemList)
{ workItemList.Add(model); }
}
else
{
switch (workItem.Type.Name)
{
case "Task":
var storyid = (workItem.WorkItemLinks.Count > 0) ? workItem.WorkItemLinks[0].TargetId : 0;
if (storyid != 0)
{
var task = new TFSTask()
{
Storyid = storyid,
ID = workItem.Id,
name = workItem.Title,
//activity = workItem.Fields["MyCompany.Activity"].Value.ToString(),
//start = (DateTime?)workItem.Fields["MyCompany.ActivityStart"].Value,
//due = (DateTime?)workItem.Fields["MyCompany.ActivityFinish"].Value,
status = workItem.State,
IterationPath = workItem.IterationPath,
Assignedto = workItem.Fields["Assigned To"].Value.ToString(),
priorty = Convert.ToInt32(workItem.Fields["Priority"].Value),
effort = Convert.ToInt32(workItem.Fields["effort"].Value),
Completed = Convert.ToInt32(workItem.Fields["Completed"].Value)
};
lock (workItemList) { workItemList.Last().Tasks.Add(task); }
}
break;
case "Bug":
var bug = new TFSIssue()
{
Storyid = (workItem.WorkItemLinks.Count > 0) ? workItem.WorkItemLinks[0].TargetId : 0,
ID = workItem.Id,
Name = workItem.Title,
//start = (DateTime?)workItem.Fields["MyCompany.ActivityStart"].Value,
//due = (DateTime?)workItem.Fields["MyCompany.ActivityFinish"].Value,
State = workItem.State,
IterationPath = workItem.IterationPath,
Assignedto = workItem.Fields["Assigned To"].Value.ToString(),
priorty = Convert.ToInt32(workItem.Fields["Priority"].Value),
effort = Convert.ToInt32(workItem.Fields["effort"].Value),
// Completed = Convert.ToInt32(workItem.Fields["Completed"].Value)
};
if (bug.Storyid != 0)
{
lock (workItemList) { workItemList.Last().Issues.Add(bug); }
}
break;
default:
break;
}
}
});
stopwatch.Stop();
var k= stopwatch.ElapsedMilliseconds;
public class WorkItemViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public string AssignedTo { get; set; }
public string WorkitemType { get; set; }
public string Priorty { get; set; }
public string IterationPath { get; set; }
public string State { get; set; }
public List<TFSIssue> Issues { get; set; }
public List<TFSTask> Tasks { get; set; }
public List<Backlogitem> PBacklog { get; set;}
public WorkItemViewModel() // Added a public constructor
{
Issues = new List<TFSIssue>();
Tasks = new List<TFSTask>();
PBacklog = new List<Backlogitem>();
}
}
public class TFSIssue
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime? Created { get; set; }
public string State { get; set; }
public DateTime? due { get; set; }
public string IterationPath { get; set; }
public string Assignedto { get; set; }
public int priorty { get; set; }
public int effort { get; set; }
public int Storyid { get; set; }
// public int Completed { get; set; }
}
public class TFSTask
{
public int ID { get; set; }
public string name { get; set; }
// public string activity { get; set; }
public string status { get; set; }
// public DateTime? start { get; set; }
// public DateTime? due { get; set; }
public string IterationPath { get; set; }
public string Assignedto { get; set; }
public int priorty { get; set; }
public int effort { get; set; }
public int Completed { get; set; }
public int Storyid { get; set; }
}
Upvotes: 0
Views: 406
Reputation: 39092
You cannot directly convert any for
loop to Parallel.For
. Parallelization has many consequences to the code you are writing. In your case the biggest problem is probably going to be the workItemList
, because it is being modified in the loop's body.
Before you parallelized the code there was no problem, because only one thread accessed this variable at one time. With Parallel.For
multiple threads may access it at once which leads to problems you are seeing. List
isn't built with parallelization support, so you have to make sure it is being modified by only one thread at one time.
The best solution would be to add locking around code that accesses the list. For example:
lock ( workItemList )
{
workItemList.Add(model);
}
Lock on an instance makes sure, that only one thread may enter the inner critical code block at once. If another thread is already executing the block, others must wait.
Upvotes: 1