C# 多个任务中的一个任务获得互斥锁的时间比其他任务长得多
形势 目前在我的项目中,我有3个C# 多个任务中的一个任务获得互斥锁的时间比其他任务长得多,c#,multithreading,concurrency,task-parallel-library,mutex,C#,Multithreading,Concurrency,Task Parallel Library,Mutex,形势 目前在我的项目中,我有3个Workers内部有一个工作循环,还有一个CommonWork类对象,它包含Work方法(DoFirstTask、DoSecondTask、DoThirdTask),Workers可以调用这些方法。每个工作方法必须相互排斥地执行。每种方法都会产生更多嵌套的任务,这些任务会一直等到完成 问题 当所有3名Worker都启动时,2名Worker以相同的速度运行,但第3名Worker落后于或1名Worker速度非常快,第2名稍慢,第3名非常慢,这取决于现实世界 奇异性 当
Workers
内部有一个工作循环,还有一个CommonWork
类对象,它包含Work
方法(DoFirstTask、DoSecondTask、DoThirdTask),Workers可以调用这些方法。每个工作
方法必须相互排斥地执行。每种方法都会产生更多嵌套的任务
,这些任务会一直等到完成
问题
当所有3名Worker
都启动时,2名Worker
以相同的速度运行,但第3名Worker
落后于或1名Worker
速度非常快,第2名稍慢,第3名非常慢,这取决于现实世界
奇异性
当只有两个工人
在工作时,他们也会很好地分担工作,并以相同的速度工作
更有趣的是,即使是第三个Worker
调用的CommonWork
方法数量更少,并且有可能执行更多的循环,但事实并非如此。我试着在下面的代码中模拟这个条件:
if (Task.CurrentId.Value < 3)
解决方案是使用
新的SempahoreSlim(1)
而不是互斥锁
(或简单的锁
,或监视器
)。仅使用SemaphoreSlim
使线程调度
成为循环,因此没有使某些线程/任务相对于其他线程“特殊”。谢谢你,阿农
如果有人能解释原因,我将不胜感激。不要使用
任务。运行获取线程池线程,然后等待阻止它。@I3arnon,不确定,你的意思是什么。我需要等待那些任务
,然后工人才能继续下一个任务=方法。这一切都很好。你根本不需要这些任务,因为你浪费了一个线程等待它们完成。只要让线程执行任务内部的工作。@I3arnon,我知道你的意思,但我需要它们。现在检查更具体的代码。我的评论仍然有效。如果您有async
功能,那么也可以使用DoXTask
方法async
,并使用SemphoreSlim
而不是互斥体。
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