【问题标题】:ConcurrentDictionary fails to find a key even if I am sure it exists即使我确定它存在,ConcurrentDictionary 也找不到密钥
【发布时间】:2013-07-01 22:21:00
【问题描述】:

在我的静态类中,我有这个:

static var cache = new ConcurrentDictionary<string, object>();

在线程 #1 我这样做:

cache.TryAdd (stringFromSomewhere, newlyCreatedObject); 
Console.WriteLine(stringFromSomewhere); // Outputs "abc"

在线程 #1 之后几秒钟,在线程 #2:

if(cache.ContainsKey(stringFromSomewhereElse))
    Console.WriteLine("Yes, it exists.");
else
    Console.WriteLine("This did not exist: " + stringFromSomewhereElse);

它输出“这不存在:abc”

然后在 Thread #2 之后的 Thread #3 几秒钟:

foreach(var kvp in cache)
{
    Console.WriteLine("string: " + kvp.Key);
    if(cache.ContainsKey(kvp.Key))
        Console.WriteLine("Yes, it exists.");
    else
        Console.WriteLine("This did not exist: " + kvp.Key);
}

我得到输出“字符串:abc”和“是的,它存在。”

在线程 #1 中,我使用 MD5 创建字符串,如下所示:

Convert.ToBase64String (md5.ComputeHash(Encoding.ASCII.GetBytes(value)))

在线程 #2 中,我从字节流中获取字符串,该字符串使用 UTF8 编码写入其中,然后再次使用 UTF8 编码从字节中读取字符串。

在线程 #3 中,我通过循环 ConcurrentDictionary 来获取字符串。

我在这里缺少什么?据我所知,线程#2 的行为应该与线程#3 一样。

我有两种可能性,我认为这两种可能性都很大:

  • 这是我不知道的某种同步问题吗?
  • 或者字符串有什么不同?当我将它输出到控制台时,它并没有什么不同。

有人有其他想法或解决方案吗?

编辑:

我像这样将数据写入流:

string data = System.Web.HttpUtility.UrlEncode(theString);
byte[] buffer = Encoding.UTF8.GetBytes (data);
NetworkStream stream = client.GetStream(); // TcpClient client;
stream.Write (buffer, 0, buffer.Length);

然后我像这样从流中读取数据:

string data = "";
NetworkStream stream = client.GetStream(); // TcpClient client;
byte[] bytes = new byte[4096];
do {   
    int i = stream.Read (bytes, 0, bytes.Length);
    data += Encoding.UTF8.GetString (bytes, 0, i);
} while(stream.DataAvailable);
string theString = HttpUtility.UrlDecode(data);

【问题讨论】:

  • 您必须提供更多代码。
  • 你想看什么?
  • 最小代码sn-p,其行为与描述相同。
  • 我添加了编辑,我描述了如何将字符串写入流并读回。
  • 当你将它输出到控制台时,输出长度并在字符串周围加上引号。听起来可能有一些空格或不可打印的字符。类似Console.WriteLine("This did not exist: '{0}', Length={1}", stringFromSomewhereElse, stringFromSomewhereElse.Length);

标签: c# string multithreading stream concurrentdictionary


【解决方案1】:

如果您将字节写入网络流,然后再将其读回,则必须在数据前面加上一个表示后面有多少字节的值,或者您需要一个数据结束标记。根据您的代码编写方式,接收代码很可能只获取部分数据。

例如,假设您的密钥是“HelloWorld”。您的发送代码将字符串发送出去。接收代码看到缓冲区中的“Hello”部分,抓取它,检查是否有更多数据可用,这并不是因为网络传输线程还没有完成将其复制到缓冲区。

所以你只得到字符串的一部分。

可能发生的另一件事是您阅读过多。如果您将两个字符串写入网络流,而您的阅读器读取这两个字符串,就好像它们是单个字符串一样,就会发生这种情况。

要做到这一点,您应该这样做:

int dataLength = buffer.Length;
byte[] lengthBuff = BitConverter.GetBytes(dataLength);
stream.Write(lengthBuff, 0, lengthBuff.Length);  // write length
stream.Write(buffer, 0, buffer.Length);  // write data

然后通过首先读取长度然后从流中读取那么多字节来读取它。

或者,您可以使用数据结束标记:

stream.Write(buffer, 0, buffer.Length);  // write data
buffer[0] = end_of_data_byte;
stream.Write(buffer, 0, 1);  // write end of data

您的阅读器会读取字节,直到它获得数据标记的结尾。

数据结束标记的用途取决于您。它应该是不会出现在正常数据流中的东西。

就个人而言,我会选择长度前缀。

【讨论】:

  • 感谢您的回答。我理解这个概念,但这并不能真正解决这里的问题。当我从 Thread #2 中的流中获取数据并将其传递给静态类以查找密钥是否存在时,它说它不存在,但仍然输出正确的字符串,如问题说明所示。
  • 另外,我可能过度简化了从流中读取的过程。我实际上读取了很多数据(但小于 4kb)并使用正则表达式从文本数据中解析出字符串。
【解决方案2】:

很难理解你的问题的流程 - 但是我注意到一件事:你在网络 Write() 之后 Flush() 吗?否则,您可能会出现写入延迟,这通常会导致与时间相关的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-24
    • 1970-01-01
    • 2013-01-04
    • 1970-01-01
    • 2022-01-17
    • 2012-06-30
    • 1970-01-01
    • 2012-05-16
    相关资源
    最近更新 更多