3

txtファイルを読み取って辞書を返すために使用される次のメソッドを取得しました。〜5MBのファイル(67000行、各行に70文字)を読み取るのに約7分かかります。

public static Dictionary<string, string> FASTAFileReadIn(string file)
{
    Dictionary<string, string> seq = new Dictionary<string, string>();

    Regex re;
    Match m;
    GroupCollection group;
    string currentName = string.Empty;

    try
    {
        using (StreamReader sr = new StreamReader(file))
        {
            string line = string.Empty;
            while ((line = sr.ReadLine()) != null)
            {
                if (line.StartsWith(">"))
                {// Match Sequence
                    re = new Regex(@"^>(\S+)");
                    m = re.Match(line);
                    if (m.Success)
                    {
                        group = m.Groups;
                        if (!seq.ContainsKey(group[1].Value))
                        {
                            seq.Add(group[1].Value, string.Empty);
                            currentName = group[1].Value;
                        }
                    }
                }
                else if (Regex.Match(line.Trim(), @"\S+").Success &&
                            currentName != string.Empty)
                {
                    seq[currentName] += line.Trim();
                }
            }
        }
    }
    catch (IOException e)
    {
        Console.WriteLine("An IO exception has benn thrown!");
        Console.WriteLine(e.ToString());
    }
    finally { }

    return seq;
}

コードのどの部分に最も時間がかかり、どのように高速化するのですか?

ありがとう

4

4 に答える 4

3

コンパイラがこれを自動的に行うことを願っていますが、最初に気付くのは、一致するすべての行で正規表現を再コンパイルしていることです。

            while ((line = sr.ReadLine()) != null)
            {
                if (line.StartsWith(">"))
                {// Match Sequence
                    re = new Regex(@"^>(\S+)");

正規表現を完全に削除できればさらに良いでしょう。ほとんどの言語は、split正規表現を頻繁に使用するある種の関数を提供します。

于 2012-07-24T03:08:42.413 に答える
2

正規表現のキャッシュとコンパイル、条件の並べ替え、トリミングの数の削減など。

public static Dictionary<string, string> FASTAFileReadIn(string file) {
    var seq = new Dictionary<string, string>();

    Regex re = new Regex(@"^>(\S+)", RegexOptions.Compiled);
    Regex nonWhitespace = new Regex(@"\S", RegexOptions.Compiled);
    Match m;
    string currentName = string.Empty;

    try {
        foreach(string line in File.ReadLines(file)) {
            if(line[0] == '>') {
                m = re.Match(line);

                if(m.Success) {
                    if(!seq.ContainsKey(m.Groups[1].Value)) {
                        seq.Add(m.Groups[1].Value, string.Empty);
                        currentName = m.Groups[1].Value;
                    }
                }
            } else if(currentName != string.Empty) {
                if(nonWhitespace.IsMatch(line)) {
                    seq[currentName] += line.Trim();
                }
            }
        }
    } catch(IOException e) {
        Console.WriteLine("An IO exception has been thrown!");
        Console.WriteLine(e.ToString());
    }

    return seq;
}

ただし、これは単純な最適化です。FASTA形式を読んで、私はこれを書きました:

public static Dictionary<string, string> ReadFasta(string filename) {
    var result = new Dictionary<string, string>
    var current = new StringBuilder();
    string currentKey = null;

    foreach(string line in File.ReadLines(filename)) {
        if(line[0] == '>') {
            if(currentKey != null) {
                result.Add(currentKey, current.ToString());
                current.Clear();
            }

            int i = line.IndexOf(' ', 2);

            currentKey = i > -1 ? line.Substring(1, i - 1) : line.Substring(1);
        } else if(currentKey != null) {
            current.Append(line.TrimEnd());
        }
    }

    if(currentKey != null)
        result.Add(currentKey, current.ToString());

    return result;
}

それが機能するかどうか教えてください。それははるかに速いはずです。

于 2012-07-24T03:14:27.787 に答える
1

BufferedStream:を使用すると、読み取り速度を大幅に向上させることができます。

using (FileStream fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
    // Use the StreamReader
}

言及されているRegex再コンパイル@sarnoldは、処理時間が最大5分である場合、おそらく最大のパフォーマンスキラーです。

于 2012-07-24T03:10:49.900 に答える
1

これが私がそれを書く方法です。詳細情報(つまり、平均的な辞書エントリの長さ)がないと、StingBuilderの容量を最適化できません。Eric J.のアドバイスに従って、を追加することもできますBufferedStream。パフォーマンスを向上させたい場合は完全に廃止するのが理想的ですRegular Expressionsが、作成と管理がはるかに簡単なので、なぜそれらを使用したいのか理解しています。

public static Dictionary<string, StringBuilder> FASTAFileReadIn(string file)
{
    var seq = new Dictionary<string, StringBuilder>();
    var regName = new Regex("^>(\\S+)", RegexOptions.Compiled);
    var regAppend = new Regex("\\S+", RegexOptions.Compiled);

    Match tempMatch = null;
    string currentName = string.Empty;
    try
    {
        using (StreamReader sReader = new StreamReader(file))
        {
            string line = string.Empty;
            while ((line = sReader.ReadLine()) != null)
            {
                if ((tempMatch = regName.Match(line)).Success)
                {
                    if (!seq.ContainsKey(tempMatch.Groups[1].Value))
                    {
                        currentName = tempMatch.Groups[1].Value;
                        seq.Add(currentName, new StringBuilder());
                    }
                }
                else if ((tempMatch = regAppend.Match(line)).Success && currentName != string.Empty)
                {
                    seq[currentName].Append(tempMatch.Value);
                }
            }
        }
    }
    catch (IOException e)
    {
        Console.WriteLine("An IO exception has been thrown!");
        Console.WriteLine(e.ToString());
    }

    return seq;
}

ご覧のとおり、StringBuilder値を追加するために最適化されたクラスを使用するように辞書を少し変更しました。また、同じ正規表現を何度も繰り返し再コンパイルしないようにするために、正規表現を1回だけプリコンパイルしました。また、「追加」ケースを抽出して、正規表現にコンパイルしました。

これがパフォーマンス面で役立つかどうか教えてください。

于 2012-07-24T03:32:38.543 に答える