... но был странный результат.
Я просматривал код в потоке повторов.Идея проста: поискать кеш, если он не в кеше, отложить и повторить попытку.Очевидно, что другой поток записывает данные в тот же кеш и использует тот же объект блокировки.
Я обнаружил, что я думал, что это потенциальная ошибка, где есть Task.Delay (1) .Wait () внутри блокировки повторапоток и мой «аргумент» / теория заключались в том, что хотя цикл повторных попыток освобождает блокировку, он все же может получить блокировку до того, как записывающий поток сможет.
Поэтому я решил посмотреть, смогу ли я быстро воспроизвести код (скорееплохо):
namespace TaskDelay
{
class Program
{
static Dictionary<int, string> dict = new Dictionary<int, string>();
static BlockingCollection<int> bc = new BlockingCollection<int>();
static ManualResetEvent resetEvent = new ManualResetEvent(false);
static ManualResetEvent nresetEvent = new ManualResetEvent(false);
static void Main(string[] args)
{
new Program().Run();
Console.Read();
}
public void Run()
{
var t = new Thread(RetryThread);
t.Start();
var v = new Thread(TryAdd);
v.Start();
bc.Add(20);
bc.Add(21);
resetEvent.Set();
}
public void RetryThread()
{
resetEvent.WaitOne();
Console.WriteLine("Starting RetryLoop");
bool done = false;
nresetEvent.Set();
while (!done)
{
done = RetryLoop(21);
}
}
public bool RetryLoop(int x)
{
Console.WriteLine($"In Retry loop {x}");
for (int i = 0; i < 5; i++)
{
lock (dict)
{
Console.WriteLine($"Entering Retry loop {x}. Count {i+1}");
if (!dict.ContainsKey(x))
{
Task.Delay(1).Wait();//Change to Thread.Sleep(1)
continue;
}
Console.WriteLine($"eXITING Retry loop {x}");
return true;
}
}
return false;
}
void TryAdd()
{
Console.WriteLine("Starting TryAdd");
nresetEvent.WaitOne();
for (int i = 0; i < 2000; i++)
{
if (i == 1500)
break;
Thread.Sleep(1);
}
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine("Exited loop");
Console.BackgroundColor = ConsoleColor.Black;
lock (dict)
{
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine("Entered lock try add");
dict[21] = "hello";
Console.WriteLine("Exit lock try add");
Console.BackgroundColor = ConsoleColor.Black;
}
}
}
}
Я попробовал 3 теста в RetryLoop со следующими результатами:
- Использование Task.Delay (1) .Wait () в блокировке.
- Использовать Thread.Sleep (1) в блокировке
- Нет задержки в блокировке
В случае 1: записывающий поток получает блокировку быстрее.Мгновенно, как только поток записи выходит из своего простого цикла счетчика.
В случаях 2 и 3: это несколько доказывает теорию, что поток записи может не получить блокировку в течение некоторого времени.Другими словами, это заняло намного больше времени.
Обратите внимание на разрыв в двух изображениях. Мой вопрос: почему случай 1 значительно быстрее?Может быть, тогда я ошибался ...
Я понимаю, что этот код не является детерминированным и может даже иметь недостатки.Открыт для альтернатив.