如果有多个线程访问,C#中的静态类和方法会变慢吗? [英] Do static classes and methods in C# get slower if accessed by multiple threads
问题描述
我在C#2010和.Net 4.0中有一个应用程序,它通过任务并行库使用多线程.其中有一些静态类和静态方法.每当在单个线程中运行静态方法时,性能就可以达到预期的效果,但是当不同线程调用同一方法时,该方法似乎会变慢,这会影响应用程序的整体性能.
任何建议或最佳做法都将受到高度赞赏.预先感谢您的答复.
更多信息:
这是一个较早使用线程池在某些部分执行线程处理的应用程序.我介绍了并行任务.因此,它是TPL和较旧的线程池的混合体.假设一个并行任务可以有多个线程.该机器具有24个CPU内核,带64GB RAM.我运行了2个进程,这些进程将拆分为5个线程,每个线程总计10个线程.在此过程中,速度变慢了.我将代码粘贴在这里,供那些希望对其进行检查并提供建议的人使用.抱歉,粘贴长代码.该代码可能没有几年前编写的所有当前最新功能.再次感谢.
Hi,
I have an application in C# 2010 and .Net 4.0 which uses multi threading through Task Parallel Library. There are some static classes and static methods within this. Whenever a static method is run in a single thread the performance is as expected but when the same method is called by different threads the method seems to get slower and this is impacting the overall performance of the application.
Any suggestion or best practices are highly appreciated. Thanks in advance of your responses.
Some more info:
This is an application which was using threadpool earlier to perform threading in some parts. I introduced parallel tasks. Hence it''s a mix up of TPL and older Thread pool. Say for example one parallel task can have multiple threads. The machine has 24 CPU cores with 64GB RAM. I ran 2 processes which would have split to 5 threads each totalling upto 10 threads. During this the process got slower. I am pasting the code here for those who would like to inspect it and provide suggestions. Sorry for pasting long code. The code may not be having all current latest features as this was coded few years ago. Thanks once again.
public static class Property11
{
/// <summary>
/// Splits agg rows to separate commands where the reference parameters are included for each command.
/// </summary>
/// <param name="worksheetID">The current worksheet ID.</param>
/// <param name="propertyID">The current property ID.</param>
/// <param name="ccrFormObj">The ccr form object.</param>
public static void SplitAggregateIncludeReferenceParameterCCRToDTH(PropertyCall propertyCallObj)
{
string worksheetID = propertyCallObj.WorksheetID;
int propertyID = propertyCallObj.PropertyID;
IDClass nextIDObj = propertyCallObj.NextIDObj;
CCRFormStructure ccrFormObj = propertyCallObj.CCRFormObj;
List<CCRFormStructure> ccrFormObjsToAdd = propertyCallObj.CCRFormObjToAddList;
DateTime dtProp = DateTime.Now;
System.Diagnostics.Debug.Print("Start time property = " + propertyCallObj.PropertyID + ", worksheet = " + propertyCallObj.WorksheetID + ": " + dtProp.ToString());
try
{
// Get all rows for worksheet
List<WorksheetRow> rowListForWorksheet =
(from wr in ccrFormObj.myWorksheetRowList
where wr.WorksheetID == worksheetID
select wr).ToList();
// Get all parameters for worksheet
List<WorksheetRowParameter> rowParameterListForWorksheet =
(from wrp in ccrFormObj.myWorksheetRowParameterList
join wr in rowListForWorksheet
on wrp.WorksheetRowID equals wr.ID
select wrp).ToList();
// Get all agg rows in worksheet
List<AggRow> aggRowsInWorksheet =
(from ar in ccrFormObj.myAggRowList
join wsrp in rowParameterListForWorksheet
on ar.WorksheetRowParameterID equals wsrp.ID
select ar).ToList();
// Get all agg row parameters in worksheet
List<AggRowParameter> aggParametersInWorksheet =
(from arp in ccrFormObj.myAggRowParameterList
join ar in aggRowsInWorksheet
on arp.AggRowID equals ar.ID
select arp).ToList();
// Get all command mappings for worksheet
List<CommandMappingObj> commandMappingListForWorksheet =
(from cm in ccrFormObj.commandMappingList
join wr in rowListForWorksheet
on cm.WorksheetRowID equals wr.ID
select cm).ToList();
// Get all parameter mappings for worksheet
List<ParameterMappingObj> parameterMappingListForWorksheet =
(from pm in ccrFormObj.parameterMappingList
join cm in commandMappingListForWorksheet
on pm.CommandMappingObjID equals cm.ID
select pm).ToList();
// Get all property objects for worksheet
List<ParameterPropertyObj> propertyList =
(from ppo in ccrFormObj.parameterPropertiesList
where ppo.ID == propertyID && ppo.WorksheetID == worksheetID
select ppo).ToList();
//List<WorksheetRow> rowsToRemove = new List<WorksheetRow>();
WorksheetRowParameter currentWorksheetRowParameter;
AggRow currentAggRow;
AggRowParameter currentAggRowParameter;
AggRow currentSteeringAggRow;
AggRowParameter currentSteeringAggRowParameter;
int newIDIndex = 0;
List<string> worksheetRowsWithoutTooLongCommandRows = new List<string>();
WorksheetRow newWSR = new WorksheetRow();
CommandMappingObj newCMO = new CommandMappingObj();
WorksheetRow newWSRForOrigRow = new WorksheetRow();
CommandMappingObj newChangeCMO = new CommandMappingObj();
List<string> steeringParameters;
IEnumerable<WorksheetRowParameter> parameterListForRow;
IEnumerable<WorksheetRowParameter> currentSteeringParameters;
string newCMOID;
ParameterMappingObj newPMO;
WorksheetRowParameter newWSRP;
string newWSRID;
string newID;
IEnumerable<string> commandsWithPropertyParameterForRow;
Hashtable htPropertyParamAndSteeringParameters = new Hashtable();
List<string> steeringParametersForProperty;
WorksheetRowParameter currentWorksheetRowPropertyParameter;
bool removeOrigRow = false;
bool firstRowForAggCreated = false;
List<WorksheetRowParameter> propParamListForFirstCreatedRow = new List<WorksheetRowParameter>();
List<string> propParamUsedAsSteeringList = new List<string>();
foreach (ParameterPropertyObj propertyParameter in propertyList)
{
if (propertyParameter.SecondaryPropertyInfo != null && propertyParameter.SecondaryPropertyInfo != "")
{
steeringParameters = propertyParameter.SecondaryPropertyInfo.Split(",".ToCharArray()).ToList();
}
else
{
steeringParameters = new List<string>();
}
htPropertyParamAndSteeringParameters.Add(propertyParameter.Parameter, steeringParameters);
}
var aggListForRow =
from ar in aggRowsInWorksheet
join arp in aggParametersInWorksheet
on ar.ID equals arp.AggRowID
select new
{
AggRow = ar,
AggRowParameter = arp
};
var worksheetRowsWithRepParam =
from wrp in rowParameterListForWorksheet
where htPropertyParamAndSteeringParameters.Contains(wrp.Parameter)
join al in aggListForRow
on wrp.ID equals al.AggRow.WorksheetRowParameterID
into aggList
where aggList.Count() > 0
select new
{
WorksheetRowParameter = wrp,
AggList = aggList
};
foreach (WorksheetRow worksheetRow in rowListForWorksheet.ToList())
{
var worksheetRowWithRepParam =
worksheetRowsWithRepParam.Where(wrp => wrp.WorksheetRowParameter.WorksheetRowID == worksheetRow.ID);
if (worksheetRowWithRepParam.Count() > 0)
{
firstRowForAggCreated = false;
var currentMappingList =
from cmo in commandMappingListForWorksheet
where cmo.WorksheetRowID == worksheetRow.ID
join pmo in parameterMappingListForWorksheet
on cmo.ID equals pmo.CommandMappingObjID
into parameterMappingList
select new
{
CommandMapping = cmo,
ParameterMappingList = parameterMappingList
};
IEnumerable<ParameterPropertyObj> sortedPropertyList =
from wrwrp in worksheetRowWithRepParam
join ppo in propertyList
on wrwrp.WorksheetRowParameter.Parameter equals ppo.Parameter
orderby wrwrp.AggList.Count() descending
select ppo;
propParamUsedAsSteeringList.Clear();
foreach (ParameterPropertyObj ppo in sortedPropertyList)
{
if (!propParamUsedAsSteeringList.Contains(ppo.Parameter))
{
var currentWorksheetRowsWithRepParam =
worksheetRowWithRepParam.Where(p => p.WorksheetRowParameter.Parameter == ppo.Parameter);
if (currentWorksheetRowsWithRepParam.Count() == 0)
{
continue;
}
var currentWorksheetRowWithRepParam = currentWorksheetRowsWithRepParam.ElementAt(0);
var currentAggList = currentWorksheetRowWithRepParam.AggList;
if (!firstRowForAggCreated)
{
currentWorksheetRowPropertyParameter = currentWorksheetRowWithRepParam.WorksheetRowParameter;
}
else
{
currentWorksheetRowPropertyParameter = propParamListForFirstCreatedRow.Where(p => p.Parameter == ppo.Parameter).ElementAt(0);
}
if (currentAggList.Count() > 1)
{
removeOrigRow = true;
steeringParametersForProperty = (List<string>)htPropertyParamAndSteeringParameters[ppo.Parameter];
currentSteeringParameters =
from wrp in rowParameterListForWorksheet
where wrp.WorksheetRowID == worksheetRow.ID
&& steeringParametersForProperty.Contains(wrp.Parameter)
select wrp;
commandsWithPropertyParameterForRow =
from cml in currentMappingList
where cml.ParameterMappingList.Count(pmo => pmo.Name == ppo.Parameter) > 0
select cml.CommandMapping.Name;
propParamUsedAsSteeringList.AddRange(
from sp in sortedPropertyList
where sp.Parameter != ppo.Parameter
join csp in currentSteeringParameters
on sp.Parameter equals csp.Parameter
select csp.Parameter);
// CREATE NEW WORKSHEET ROWS FOR EACH BUT THE FIRST AGG ROW PARAMETER
for (int i = 0; i < currentAggList.Count(); i++)
{
currentAggRow = currentAggList.ElementAt(i).AggRow;
currentAggRowParameter = currentAggList.ElementAt(i).AggRowParameter;
if (i == 0)
{
currentWorksheetRowPropertyParameter.Value = currentAggRowParameter.Value;
if (!firstRowForAggCreated)
{
propParamListForFirstCreatedRow.Clear();
newWSRID = newIDIndex.ToString().PadLeft(3, '0');
newID = newWSRID;
if (!worksheetRow.ID.Contains(','))
{
newID = "," + newWSRID;
}
newWSRForOrigRow = new WorksheetRow
{
ID = worksheetRow.ID + newID,
OriginalWorksheetRowID = worksheetRow.OriginalWorksheetRowID,
WorksheetID = worksheetRow.WorksheetID
};
ccrFormObj.myWorksheetRowList.Add(newWSRForOrigRow);
parameterListForRow =
from wrp in rowParameterListForWorksheet
where wrp.WorksheetRowID == worksheetRow.ID
select wrp;
foreach (WorksheetRowParameter currentParameter in parameterListForRow)
{
newID = "";
if ((currentParameter.ID != null) && (!currentParameter.ID.Contains(',')))
{
newID = ",";
}
newID += newIDIndex.ToString().PadLeft(3, '0');
newWSRP = new WorksheetRowParameter
{
ID = currentParameter.ID + newID,
OriginalParameterID = currentParameter.OriginalParameterID,
WorksheetRowID = newWSRForOrigRow.ID,
Parameter = currentParameter.Parameter,
Value = currentParameter.Value,
Disabled = currentParameter.Disabled
};
if (htPropertyParamAndSteeringParameters.Contains(newWSRP.Parameter)
&& newWSRP.Parameter != ppo.Parameter)
{
// TODO: IF AGG, TAKE AGG POS VALUE
var steeringParamAggList =
from wrwrp in worksheetRowWithRepParam
where wrwrp.WorksheetRowParameter.Parameter == newWSRP.Parameter
select wrwrp.AggList;
if (steeringParamAggList.Count() > 0)
{
if (steeringParamAggList.ElementAt(0).Count() > i)
{
currentSteeringAggRow = steeringParamAggList.ElementAt(0).ElementAt(i).AggRow;
currentSteeringAggRowParameter = steeringParamAggList.ElementAt(0).ElementAt(i).AggRowParameter;
newWSRP.Value = currentSteeringAggRowParameter.Value;
ccrFormObj.myAggRowParameterList.Remove(currentSteeringAggRowParameter);
ccrFormObj.myAggRowList.Remove(currentSteeringAggRow);
ccrFormObj.myWorksheetRowParameterList.Add(newWSRP);
}
}
else
{
ccrFormObj.myWorksheetRowParameterList.Add(newWSRP);
}
propParamListForFirstCreatedRow.Add(newWSRP);
}
else
{
ccrFormObj.myWorksheetRowParameterList.Add(newWSRP);
}
}
foreach (var currentMapping in currentMappingList)
{
// Re-point original command mapping to new row
newCMOID = newIDIndex.ToString().PadLeft(3, '0');
if (!currentMapping.CommandMapping.ID.Contains(','))
{
newID = "," + newCMOID;
}
// Create new command mapping object
newCMO = new CommandMappingObj
{
ID = currentMapping.CommandMapping.ID + newID,
Name = currentMapping.CommandMapping.Name,
WorksheetRowID = newWSRForOrigRow.ID
};
ccrFormObj.commandMappingList.Add(newCMO);
foreach (ParameterMappingObj pmo in currentMapping.ParameterMappingList)
{
newPMO = new ParameterMappingObj
{
Name = pmo.Name,
CommandMappingObjID = newCMO.ID
};
ccrFormObj.parameterMappingList.Add(newPMO);
}
}
firstRowForAggCreated = true;
}
}
else
{
newWSRID = newIDIndex.ToString().PadLeft(3, '0');
newID = newWSRID;
if (!worksheetRow.ID.Contains(','))
{
newID = "," + newWSRID;
}
newWSR = new WorksheetRow
{
ID = worksheetRow.ID + newID,
OriginalWorksheetRowID = worksheetRow.OriginalWorksheetRowID,
WorksheetID = worksheetRow.WorksheetID
};
ccrFormObj.myWorksheetRowList.Add(newWSR);
foreach (WorksheetRowParameter currentSteeringParameter in currentSteeringParameters)
{
newID = "";
if ((currentSteeringParameter.ID != null) && (!currentSteeringParameter.ID.Contains(',')))
{
newID = ",";
}
newID += newIDIndex.ToString().PadLeft(3, '0');
newWSRP = new WorksheetRowParameter
{
ID = currentSteeringParameter.ID + newID,
OriginalParameterID = currentSteeringParameter.OriginalParameterID,
WorksheetRowID = newWSR.ID,
Parameter = currentSteeringParameter.Parameter,
Value = currentSteeringParameter.Value,
Disabled = currentSteeringParameter.Disabled
};
var steeringParamAggList =
from wrwrp in worksheetRowWithRepParam
where wrwrp.WorksheetRowParameter.Parameter == newWSRP.Parameter
select wrwrp.AggList;
if (steeringParamAggList.Count() > 0)
{
if (steeringParamAggList.ElementAt(0).Count() > i)
{
currentSteeringAggRow = steeringParamAggList.ElementAt(0).ElementAt(i).AggRow;
currentSteeringAggRowParameter = steeringParamAggList.ElementAt(0).ElementAt(i).AggRowParameter;
newWSRP.Value = currentSteeringAggRowParameter.Value;
ccrFormObj.myAggRowParameterList.Remove(currentSteeringAggRowParameter);
ccrFormObj.myAggRowList.Remove(currentSteeringAggRow);
ccrFormObj.myWorksheetRowParameterList.Add(newWSRP);
}
}
else
{
ccrFormObj.myWorksheetRowParameterList.Add(newWSRP);
}
}
// Add rep param
newID = "";
if ((currentWorksheetRowPropertyParameter.ID != null) && (!currentWorksheetRowPropertyParameter.ID.Contains(',')))
{
newID = ",";
}
newID += newIDIndex.ToString().PadLeft(3, '0');
newWSRP = new WorksheetRowParameter
{
ID = currentWorksheetRowPropertyParameter.ID + newID,
OriginalParameterID = currentWorksheetRowPropertyParameter.OriginalParameterID,
WorksheetRowID = newWSR.ID,
Parameter = currentWorksheetRowPropertyParameter.Parameter,
Value = currentAggRowParameter.Value,
Disabled = currentWorksheetRowPropertyParameter.Disabled
};
ccrFormObj.myWorksheetRowParameterList.Add(newWSRP);
foreach (var currentMapping in currentMappingList)
{
if (commandsWithPropertyParameterForRow.Contains(currentMapping.CommandMapping.Name))
{
newCMOID = newIDIndex.ToString().PadLeft(3, '0');
if (!currentMapping.CommandMapping.ID.Contains(','))
{
newID = "," + newCMOID;
}
// Create new command mapping object
newCMO = new CommandMappingObj
{
ID = currentMapping.CommandMapping.ID + newID,
Name = currentMapping.CommandMapping.Name,
WorksheetRowID = newWSR.ID
};
ccrFormObj.commandMappingList.Add(newCMO);
foreach (ParameterMappingObj pmo in currentMapping.ParameterMappingList)
{
if ((pmo.Name == ppo.Parameter) || (currentSteeringParameters.Count(p => p.Parameter == pmo.Name) > 0))
{
newPMO = new ParameterMappingObj
{
Name = pmo.Name,
CommandMappingObjID = newCMO.ID
};
ccrFormObj.parameterMappingList.Add(newPMO);
}
}
}
}
}
newIDIndex++;
ccrFormObj.myAggRowParameterList.Remove(currentAggRowParameter);
ccrFormObj.myAggRowList.Remove(currentAggRow);
}
}
else
{
currentAggRow = currentAggList.ElementAt(0).AggRow;
currentAggRowParameter = currentAggList.ElementAt(0).AggRowParameter;
currentWorksheetRowPropertyParameter.Value = currentAggRowParameter.Value;
ccrFormObj.myAggRowParameterList.Remove(currentAggRowParameter);
ccrFormObj.myAggRowList.Remove(currentAggRow);
}
}
}
if (removeOrigRow)
{
FormLogicCommon.RemoveObjectsForWorksheetRow(worksheetRow, ref ccrFormObj);
removeOrigRow = false;
}
}
}
ccrFormObjsToAdd.Add(ccrFormObj);
}
catch (Exception exc)
{
if (exc.InnerException == null)
throw new Exception("", exc);
else
throw exc;
}
finally
{
System.Diagnostics.Debug.Print("Processing time property = " + propertyID + ", worksheet = " + worksheetID + ": " + DateTime.Now.Subtract(dtProp));
}
}
}
推荐答案
简单的答案是否定的,当在多个线程上运行时,静态类和方法不会变慢.他们真的不能.但是,这并不意味着他们访问的资源不会变慢.例如,如果每个线程正在下载文件,并且线程的总数使网络连接最大,则每个线程的执行速度将比单独运行并且拥有网络连接的全部资源的速度慢.线程可以充分利用您的处理器,但是有时您的处理器并不是唯一的限制因素.
The simple answer is no, static classes and methods will not get slower when run on multiple threads. They really cannot. However, that doesn''t mean that the resources they access won''t run slower. For example, if each thread is downloading a file and the combined number of threads maxes out your network connection, each will perform slower than if they were each run seperately and had the full resources of the network connection to themselves. Threading works to make full use of your processor but sometimes your processor isn''t the only limiting factor.
不,不是.但是,无论您用于数据存储的什么,都可能会不满意.
我也不会去挖掘那堆代码来找到它.看到那一刻,我的头突然爆炸了.我认为您确实需要尝试将其分解为较小的方法.您可能会发现可以在多个线程上做一些事情,而不能做其他事情.
No, it doesn''t. But, whatever you''re using for a data store might not appreciate it.
I''m not about to go digging through that pile of code to find it either. My head exploded when I saw that. I think you REALLY need to try and break that down into smaller methods. You may find out that you can do some things in that pile on multiple threads, but not others.
这篇关于如果有多个线程访问,C#中的静态类和方法会变慢吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!