ConcurrentDictionary не может найти ключ, даже если я уверен, что он существует

В моем статическом классе у меня есть это:

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»

Затем в потоке № 3 через пару секунд после потока № 2:

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);

person Lasse    schedule 01.07.2013    source источник
comment
Вы должны предоставить больше кода.   -  person Hamlet Hakobyan    schedule 02.07.2013
comment
Что вы хотите увидеть?   -  person Lasse    schedule 02.07.2013
comment
Минимальный фрагмент кода, который ведет себя, как описано.   -  person Hamlet Hakobyan    schedule 02.07.2013
comment
Я добавил редактирование, где я описываю, как я записываю строку в поток и считываю ее обратно.   -  person Lasse    schedule 02.07.2013
comment
Может быть, вы можете показать код, где вы работаете с кешем?   -  person Hamlet Hakobyan    schedule 02.07.2013
comment
Это действительно весь код, который выполняется, когда я обращаюсь к кешу. Я добавил цикл foreach в поток № 3. У меня есть сильное ощущение, что я буду довольно много фейспалмить после того, как исправлю это.   -  person Lasse    schedule 02.07.2013
comment
Вы пробовали сбрасывать поток?   -  person Nicole DesRosiers    schedule 02.07.2013
comment
Я не вижу, что хорошего в этом, так как очевидно, что он отправляется клиенту через tcpclient, который возвращает данные, и я могу их получить. Чтобы быть более ясным: поток № 1 отправляет данные через поток, поток № 2 получает данные из потока, когда клиент отправляет их. При выводе строки на консоль я проверяю, что она идентична отправленной мной строке.   -  person Lasse    schedule 02.07.2013
comment
Когда вы выводите его на консоль, выведите длину и заключите строку в кавычки. Похоже, там могут быть пробелы или непечатаемые символы. Что-то вроде Console.WriteLine("This did not exist: '{0}', Length={1}", stringFromSomewhereElse, stringFromSomewhereElse.Length);   -  person Jim Mischel    schedule 02.07.2013
comment
@JimMischel Спасибо. Кажется, действительно есть \r в конце строки, которую я получаю из потока.   -  person Lasse    schedule 02.07.2013


Ответы (2)


Если вы записываете байты в сетевой поток, а затем читаете их обратно, вам нужно либо предварить данные значением, указывающим, сколько байтов следует за ними, либо вам нужен маркер конца данных. Судя по тому, как написан ваш код, вполне возможно, что код приема получает только часть данных.

Представьте, например, что ваш ключ — «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

И ваш читатель читает байты, пока не дойдет до маркера конца данных.

Что вы используете для маркера конца данных, зависит от вас. Это должно быть что-то, чего не будет в обычном потоке данных.

Лично я бы выбрал префикс длины.

person Jim Mischel    schedule 02.07.2013
comment
Спасибо за ваш ответ. Я понимаю эту концепцию, но на самом деле это не решает проблему. Когда я получаю данные из потока в Thread #2 и передаю их статическому классу, чтобы узнать, существует ли ключ, он говорит, что он не существует, но все равно выводит правильную строку, как показано в объяснении проблемы. - person Lasse; 02.07.2013
comment
Также я, возможно, упростил процесс чтения из потока. На самом деле я читаю довольно много данных (но менее 4 КБ) и анализирую строку из текстовых данных с помощью регулярных выражений. - person Lasse; 02.07.2013

Трудно понять ход вашего вопроса - однако я замечаю одну вещь: вы Flush() после сети Write()? В противном случае вы можете получить задержки при записи, что в целом может вызвать проблемы, связанные со временем.

person steve cook    schedule 02.07.2013