为什么在使用Parallel.For时会导致ArgumentOutOfRangeException

本文关键字:ArgumentOutOfRangeException For Parallel 为什么 | 更新日期: 2023-09-27 18:20:18

我尝试过写一些东西来散列数字,并根据列表检查它们,看看是否存在匹配的散列。

我使用for循环处理得很好,然后我决定尝试使用Parallel来加快速度。不幸的是,这会导致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;
    }
}

调用加密程序时,错误随机发生。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();
}

我有两个问题:

  1. 为什么我会得到一个例外
  2. 我使用BlockingCollection来实现我想要实现的目标是对的吗

为什么在使用Parallel.For时会导致ArgumentOutOfRangeException

StringBuilder不是线程安全的:

任何实例成员都不能保证是线程安全的。

但是,对于所有的EncryptCardNumber调用,您似乎都在使用相同的StringBuilder实例。当一个线程执行.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();
相关文章:
  • 没有找到相关文章