СИТУАЦИЯОдин из нескольких задач приобретает замок в Mutex гораздо дольше, чем другие задачи сделать
В настоящее время в моем проекте у меня есть 3 Workers
, которые имеют рабочую петлю внутри, и один CommonWork
объект класса, который содержит Work
методы (DoFirstTask, DoSecondTask, DoThirdTask), который может вызвать Workers
. Каждый метод Work
должен выполняться взаимно исключительно по отношению друг к другу. Каждый из методов порождает больше вложенных Tasks
, которые ждут, пока они не закончатся.
ПРОБЛЕМА
Когда все 3 Workers
запущены, 2 Workers
выполняют несколько с той же скоростью, но третий Worker
отстает или первый Worker
супер-быстрый, второй немного медленнее, и третий является очень медленно, это зависит от реального мира.
странностей
Когда только 2 Workers
работают, они разделяют работу хорошо тоже, и выполнять с той же скоростью.
Что более интересно, что даже третий Worker
вызывает меньшее число CommonWork
методов, и имеет потенциал для выполнения более цикла циклов, это не так. Я пытался имитировать, что в приведенном ниже коде с условием:
if (Task.CurrentId.Value < 3)
При отладке, я обнаружил, что третий Worker
ждет на приобретение блокировку на Mutex
значительно дольше, чем другие Workers
. Иногда другие два Workers
просто работают взаимозаменяемо, а третий продолжает ждать Mutex.WaitOne()
; Наверное, не введя его, потому что другие Workers
не имеют проблем с приобретением этого замка!
ЧТО Я УЖЕ ПРОБОВАЛИ
Я попытался начиная Worker
Tasks
, как TaskCreateOptions.LongRunning
, но ничего не изменилось. Я также попытался сделать вложеннуюTasks
быть ребенокTasks
, указав TaskCreateOpions.AttachedToParent
, думая, что это может быть связано с локальных очередей и планирования, но, видимо, это не так.
УПРОЩЕННЫЙ КОД
Ниже приведен упрощенный код моего реального приложения. Грустный сказать, я не мог воспроизвести эту ситуацию в этом простом примере:
class Program
{
public class CommonWork
{
private Mutex _mutex;
public CommonWork() { this._mutex = new Mutex(false); }
private void Lock() { this._mutex.WaitOne(); }
private void Unlock() { this._mutex.ReleaseMutex(); }
public void DoFirstTask(int taskId)
{
this.Lock();
try
{
// imitating sync work from 3rd Party lib, that I need to make async
var t = Task.Run(() => {
Thread.Sleep(500); // sync work
});
... // doing some work here
t.Wait();
Console.WriteLine("Task {0}: DoFirstTask - complete", taskId);
}
finally { this.Unlock(); }
}
public void DoSecondTask(int taskId)
{
this.Lock();
try
{
// imitating sync work from 3rd Party lib, that I need to make async
var t = Task.Run(() => {
Thread.Sleep(500); // sync work
});
... // doing some work here
t.Wait();
Console.WriteLine("Task {0}: DoSecondTask - complete", taskId);
}
finally { this.Unlock(); }
}
public void DoThirdTask(int taskId)
{
this.Lock();
try
{
// imitating sync work from 3rd Party lib, that I need to make async
var t = Task.Run(() => {
Thread.Sleep(500); // sync work
});
... // doing some work here
t.Wait();
Console.WriteLine("Task {0}: DoThirdTask - complete", taskId);
}
finally { this.Unlock(); }
}
}
// Worker class
public class Worker
{
private CommonWork CommonWork { get; set; }
public Worker(CommonWork commonWork)
{ this.CommonWork = commonWork; }
private void Loop()
{
while (true)
{
this.CommonWork.DoFirstTask(Task.CurrentId.Value);
if (Task.CurrentId.Value < 3)
{
this.CommonWork.DoSecondTask(Task.CurrentId.Value);
this.CommonWork.DoThirdTask(Task.CurrentId.Value);
}
}
}
public Task Start()
{
return Task.Run(() => this.Loop());
}
}
static void Main(string[] args)
{
var work = new CommonWork();
var client1 = new Worker(work);
var client2 = new Worker(work);
var client3 = new Worker(work);
client1.Start();
client2.Start();
client3.Start();
Console.ReadKey();
}
} // end of Program
Не используйте 'Task.Run', чтобы получить поток ThreadPool, а затем' Wait', чтобы заблокировать его. – i3arnon
@ I3arnon, не уверен, что вы имеете в виду. Мне нужно, чтобы эти «Задачи» ожидались до того, как «Рабочий» может перейти к следующему методу task =. Все в порядке с этим. – Gabrielius
Вам вообще не нужны эти задачи, потому что вы тратите поток, ожидающий их завершения. Просто попросите поток выполнить работу внутри задачи. – i3arnon