【问题标题】:KeyNotFound Exception when Key Present in Dictionary?字典中存在键时出现 KeyNotFound 异常?
【发布时间】:2015-05-03 20:38:50
【问题描述】:

我有一个非常详细的字典,它存储 350 个键,每个键都是一个 3 字节的字节数组。这本字典用于解释来自自制硬件的传入数据。

在对应用程序进行压力测试时,我遇到了一个奇怪的错误,它告诉我有一个KeyNotFoundException。奇怪的是字典里有钥匙,而我正盯着它看。字典使用了一个特殊的比较器,这可能是问题的原因:

private static Dictionary<byte[ ], string> PlayerMap =
    new Dictionary<byte[ ], string>( new ByteArrayComparator( ) );

public class ByteArrayComparator : IEqualityComparer<byte[ ]> {
    public bool Equals( byte[ ] left, byte[ ] right ) {
        if ( left == null || right == null )
            return left == right;
        return left.SequenceEqual( right );
    }

    public int GetHashCode( byte[ ] Key ) {
        if ( Key == null )
            throw new ArgumentNullException( "Key" );
        return Key.Sum( B => B );
    }
}

只有当我模拟用户以疯狂的速度按下按钮时才会发生这种情况,这意味着字典被多次查询键。

为什么会这样?比较器有问题吗?

编辑

为了清楚起见,控制器异步运行(因为它需要能够处理来自多个不同来源的传入数据)。我不想发布控制器的所有源代码,因为有很多,其中一些是敏感的,但我将发布这两个处理控件初始化的方法和它侦听传入数据的方法:

private static void Initialize(
    string DevicePath,
    R3Controller.HIDP_CAPS Capabilities,
    R3Controller.HIDD_ATTRIBUTES Attributes ) {

    R3Controller.hRead = R3Controller.OpenDevice( DevicePath );
    R3Controller.hWrite = R3Controller.OpenDevice( DevicePath );

    R3Controller.fsRead = new FileStream( hRead, FileAccess.ReadWrite, Capabilities.OutputReportByteLength, false );
    R3Controller.fsWrite = new FileStream( hWrite, FileAccess.ReadWrite, Capabilities.OutputReportByteLength, false );

    if ( R3Controller.fsRead.CanRead ) {
        R3Controller.barData = new byte[R3Controller.devCapabilities.Value.InputReportByteLength];
        if ( R3Controller.fsRead.CanRead )
            R3Controller.fsRead.BeginRead( R3Controller.barData, 0, R3Controller.barData.Length,
                new AsyncCallback( R3Controller.Listen ), R3Controller.barData );
        else
            throw new Exception( "R3 Controller Can't Read Incoming Data" );
    }
}

private static void Listen( IAsyncResult IAR ) {
    R3Controller.fsRead.EndRead( IAR );
    if ( R3Controller.fsRead.CanRead )
        R3Controller.fsRead.BeginRead( R3Controller.barData, 0, R3Controller.barData.Length,
            new AsyncCallback( R3Controller.Listen ), R3Controller.barData );
    else
        throw new Exception( "R3 Controller Can't Read Incoming Data" );
    R3InputEventArgs Args = new R3InputEventArgs( R3Controller.barData );
    if ( R3Controller.Locked || R3Controller.LockedControllers.Contains( Args.Controller ) ) {
        //Respond to locked presses if necessary...
        if ( R3Controller._LockedFeedback != null )
            R3Controller._LockedFeedback( null, Args );
        /*GetInvocationList( ).ToList( ).ForEach( E => (
            E.Clone( ) as EventHandler<R3InputEventArgs> ).BeginInvoke( null, Args, R3Controller.Heard, null ) );*/
    } else if ( R3Controller._ButtonPressed != null )
        R3Controller._ButtonPressed(null, Args);/*.GetInvocationList( ).ToList( ).ForEach(
            E => ( E.Clone( ) as EventHandler<R3InputEventArgs> ).BeginInvoke( null, Args, R3Controller.Heard, null ) );*/
}

【问题讨论】:

  • 由于您提到这种情况仅在您非常快速地执行操作时才会发生,因此可能是并发问题。你看过ConcurrentDictionary吗?
  • 如果您的密钥是 3 个字节,您可能希望生成不同的哈希码:(((int)key[0] &lt;&lt; 16) | key[1] &lt;&lt; 8 | key[2]).GetHashCode(); 但正如@cost 所指出的,这似乎不是与比较器相关的问题。更有可能是线程竞争条件。
  • 您是在阅读还是同时在写作?如果是这样,你应该把它放在问题中。那里的代码现在无法让我们重现该问题。
  • 我不是反对者,但也许人们认为缺乏信息。是否涉及多线程?字典是否在被访问的同时更新?
  • 阵列的原因是因为自制的硬件......以次充好。很久以前创建它时,创建它的人不知道二进制,因此设置完全不正常。我本可以使用基本的数学来解释传入的数据,但由于传入的数据都是乱七八糟的,这是不可能的,必须硬编码,这让我讨厌我的生活。

标签: c# multithreading asynchronous dictionary keynotfoundexception


【解决方案1】:

如果您同时/关闭时间执行读取和写入操作,Dictionary 类本身不是线程安全的。因此,如果很多线程都非常快速地访问它,您可能会遇到各种有趣的问题。由于您提到这仅在您非常快速地执行操作时才会发生,因此很有可能是问题所在。 据我所知,只执行读取而不执行写入应该不会对Dictionary 造成任何问题。

如果您使用的是 .NET 4+,则有一个名为 ConcurrentDictionary 的线程安全版本的 Dictionary,专门用于此类情况。

【讨论】:

  • 只要没有写操作,读字典就是线程安全的。
  • @PatrickHofman 你是对的。提问者没有说明他们是否正在添加新记录,但我会编辑我的答案以更具体
  • 字典只读取自;从未写入,除非在初始化期间...尽管字典本身作为静态值存储在一些快速连续创建的 EventArgs 中。这很可能是问题所在(在这种情况下,这是我的一个非常愚蠢和业余的错误)。我将尝试使用我创建的 EventArgs 类之外的常规字典。
  • 如果事件不同步,则没有问题。如果它们是异步的...
  • 它们肯定是异步的。
猜你喜欢
  • 2011-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-21
  • 2015-08-29
  • 2011-12-30
相关资源
最近更新 更多