C#文件迭代性能-值得绕过字符串.性能为IsNullOrEmpty



当前正在编写一个文件解析器,该解析器逐行运行数据文件并清理数据。性能是此应用程序的一个重要考虑因素。用户为数据列分配标签,让流程知道哪一列代表什么类型的数据,即哪一列是姓氏字段,哪一个是地址字段,哪是电话号码等等

我刚写完一堆清除电话号码的代码,并像这样应用:

public void CleanPhoneFields(FileRow row, List<Mapping> mappings)
{
    // this will return empty if there's no field mapped with the "Telephone Number" tag
    string phoneNumber = GetValueByAssignedLabel(row, mappings, "Telephone Number"); 
    if(!string.IsNullOrEmpty(phoneNumber))
    {
        CleanTelephoneNumber(phoneNumber);
    }
}       
public void ProcessFile(FileContents fileContents)
{
    foreach (FileRow row in fileContents.FileRows)
    {
        // does other cleaning functions too
        CleanPhoneFields(row, fileContents.Mappings, fc);
    }
}

然后我意识到,逐行检查电话字段是没有必要的——文件中的第一行是这样,所有行都是这样。所以我最好这样做:

public void CleanPhoneFields(FileRow row, List<Mapping> mappings)
{
    // this will return empty if there's no field mapped with the "Telephone Number" tag
    string phoneNumber = GetValueByAssignedLabel(row, mappings, "Telephone Number");
    CleanTelephoneNumber(phoneNumber);
}       
public void ProcessFile(FileContents fileContents)
{
    bool firstLine = true;
    bool cleanPhoneNeeded = false;
    foreach (FileRow row in fileContents.FileRows)
    {
        if(firstLine)
        {
            cleanPhoneNeeded = !string.IsNullOrEmpty(GetValueByAssignedLabel(row, fileContents.Mappings, "Telephone Number"));
            firstLine = false;
        }
        if(cleanPhoneNeeded)
        {
            CleanPhoneFields(row, fileContents.Mappings, fc);
        }
    }
}

我仍然需要去获取每一行的字段值,所以在这种情况下,我所"保存"的只是取消对字符串的调用。每行为IsNullOrEmpty。另一方面,第二个代码(在我看来)可读性稍差,并且丢失了一些防御性代码。

正在摆脱字符串。IsNullOrEmpty会在处理周期方面为我节省很多吗?第二种方法的小缺点值得吗。或者有更好的方法来解决这个问题吗?

使用System.Diagnostics命名空间中的Stopwatch类,您可以测量程序执行所需的时间(以毫秒为单位)。

尝试使用和不使用空和空检查器(尽管毫无疑问,有很多可测量的差异)

更多信息请点击此处:https://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch(v=vs.110).aspx

IMO string.IsNullOrEmpty调用的影响可以忽略不计。

不过,第二个解决方案的好处是,它消除了整个CleanPhoneFields调用,更重要的是,消除了似乎是最慢部分的GetValueByAssignedLabel调用(除了实际的Clean部分,当需要时无法避免)。

然而,我会对原始过程进行稍微不同的重构,在可读性和性能之间保持平衡。

首先,我将使用CleanPhoneFields方法返回bool:

public bool CleanPhoneFields(FileRow row, List<Mapping> mappings)
{
    // this will return empty if there's no field mapped with the "Telephone Number" tag
    string phoneNumber = GetValueByAssignedLabel(row, mappings, "Telephone Number"); 
    if(string.IsNullOrEmpty(phoneNumber)) return false;
    CleanTelephoneNumber(phoneNumber);
    return true;
}

那么主要的方法可能是这样的:

public void ProcessFile(FileContents fileContents)
{
    bool cleanPhoneFields = true;
    foreach (FileRow row in fileContents.FileRows)
    {
        if (cleanPhoneFields)
            cleanPhoneFields = CleanPhoneFields(row, fileContents.Mappings, fc);
        // Other stuff
    }
}

string.IsNullOrEmpty实际上没有成本(无论如何都不用担心)

另一方面,您可能想做的是将"电话号码"声明为private const字段,以防止每次调用CleanPhoneFields方法时都创建它。

您也可以使用string.Intern来防止。。。

最新更新