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

C# 为什么在使用Parallel.For时会导致ArgumentOutOfRangeException?,c#,multithreading,blockingcollection,parallel.for,C#,Multithreading,Blockingcollection,Parallel.for,我尝试过写一些东西来散列数字,并对照列表检查它们,看看是否存在匹配的散列 我使用for循环工作得很好,然后我决定尝试使用Parallel来加快速度 public class HashCompare { private string encryptedCardNumber; private Encrypter encrypter; private BlockingCollection<string> paraCardNumberList; public

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

我使用for循环工作得很好,然后我决定尝试使用Parallel来加快速度

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;
    }
}
公共类HashCompare
{
私有字符串加密卡号;
专用加密机;
私人封锁收集助理卡号码列表;
公共字符串比较(字符串哈希)
{
bool exists=Lookup.hashExists(散列);
如果(存在)
{
string unencryptedCardNumber=Lookup.GetUnencryptedCardNumber(哈希);
返回未加密的卡号;
}
返回null;
}
公共封锁收集PLCompareAll()
{
paraCardNumberList=新建BlockingCollection();
平行。对于(100000,999999,i=>
{
encrypter=新的加密程序();
encryptedCardNumber=encrypter.EncryptCardNumber(i.ToString());
var结果=比较(加密卡号);
如果(结果!=null)
{
paraCardNumberList.Add(结果);
}
});
paraCardNumberList.CompleteAdding();
返回paraCardNumberList;
}
}
调用encrypter.EncryptCardNumber(似乎在returnValue.ToString()上)时随机发生错误

私有StringBuilder返回值
公共字符串加密卡号(字符串str)
{
尝试
{
var sha1=sha1.Create();
byte[]hashData=sha1.ComputeHash(Encoding.Default.GetBytes(str));
returnValue=新的StringBuilder();
for(int i=0;i
我有两个问题:

  • 为什么我会有例外
  • 我使用BlockingCollection来实现我的目标对吗
  • 非线程安全:

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

    但您似乎在所有
    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();
    

    您的代码无法编译。请张贴真实的代码。编辑-希望这是好的!你说你在加密这张卡,但实际上你只是在对它进行哈希运算。而你散列的方式是非常不安全的。您应该使用
    SecureString
    而不是
    string
    ,并使用安全哈希,如bcrypt。太好了,非常感谢。很好地解释了,我已经对StringBuilder进行了更改,它工作起来很有魅力,现在我将实施您的其他建议。
    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();