1

数字をハッシュする何かを書き、それらをリストと照合して、一致するハッシュが存在するかどうかを確認してみました。

for ループを使用してこれを正常に動作させた後、Parallel.For を使用してスピードアップを試みることにしました - 残念ながら、これによりデバッグに問題がある ArgumentOutOfRangeException が発生します。

public class HashCompare
{
    private string encryptedCardNumber;
    private Encrypter encrypter;
    private BlockingCollection<string> paraCardNumberList;

    public string Compare(string hash)
    {
        bool exists = Lookup.hashExists(hash);

        if (exists)
        {
            string unencryptedCardNumber = Lookup.GetUnencryptedCardNumber(hash);
            return unencryptedCardNumber;
        }
        return null;
    }

        public BlockingCollection<string> PLCompareAll()
    {

        paraCardNumberList = new BlockingCollection<string>();

        Parallel.For(100000, 999999, i =>               
        {
            encrypter = new Encrypter();

            encryptedCardNumber = encrypter.EncryptCardNumber(i.ToString());
            var result = Compare(encryptedCardNumber);

            if (result != null)
            {
                paraCardNumberList.Add(result);
            }
        });
        paraCardNumberList.CompleteAdding();

        return paraCardNumberList;
    }
}

エラーは、encrypter.EncryptCardNumber を呼び出すときにランダムに発生します (returnValue.ToString() のようです)。

private StringBuilder returnValue

public string EncryptCardNumber(string str)
{
    try
    {
        var sha1 = SHA1.Create();
        byte[] hashData = sha1.ComputeHash(Encoding.Default.GetBytes(str));
        returnValue = new StringBuilder();

        for (int i = 0; i < hashData.Length; i++)
        {
            returnValue.Append(hashData[i].ToString("x2"));
        }
    }
    catch (Exception ex)
    {
        string strerr = "Error in hash code: " + ex.Message;
    }
    return returnValue.ToString();
}

2 つの質問があります。

  1. 例外が発生するのはなぜですか?
  2. 私が達成しようとしていることに BlockingCollection を使用する権利はありますか?
4

1 に答える 1

2

StringBuilderスレッドセーフではありません:

インスタンス メンバーは、スレッド セーフであるとは限りません。

しかしStringBuilder、すべてのEncryptCardNumber呼び出しで の同じインスタンスを使用しているようです。.ToString()あるスレッドが実行している間に別のスレッドがさらに文字を追加しようとしているときに、競合状態が発生することは驚くべきことではありません。

これらのスレッドをすべて上書きして、互いの StringBuilder のインスタンスに追加するつもりは実際にはないと思います。そのクラスのフィールドではなく、オブジェクトをローカル変数として宣言してみてください。などの他の変数にも同じ原則が適用される可能性がありますencrypter

あなたBlockingCollection<>の に関しては、それはおそらく良いアプローチですが、個人的にはもう少し機能的なものを使いたいと思います:

return Enumerable.Range(100000, 999999)
    .AsParallel() // One line to make this parallel
    .Select(i => new Encrypter().EncryptCardNumber(i.ToString())
    .Select(Compare)
    .Where(hash => hash != null)
    .ToList();
于 2014-08-31T16:29:27.507 に答える