状况
目前在我的项目中,我有3个Workers
内部有一个工作循环,还有一个CommonWork
类对象,其中包含Work
个方法( DoFirstTask,DoSecondTask,DoThirdTask < / {>)Workers
可以调用。每个Work
方法必须相互独立地执行其他方法。每个方法都会生成更多嵌套的Tasks
,等待它们完成。
问题
当所有3 Workers
开始时,2 Workers
以相同的速度执行,但第3 Worker
落后于或第1 Worker
是超级快,第二慢一点,第三慢很慢,这取决于现实世界。
BIZARRENESS
当只有2 Workers
正在工作时,他们也能很好地分享工作,并以相同的速度执行。
更有趣的是,即使是第3 Worker
次调用的CommonWork
方法数量也会减少,并且有可能执行更多 循环 循环,它不是。我尝试在下面的代码中用条件模拟它:
if (Task.CurrentId.Value < 3)
调试时,我发现第3 Worker
号等待获取Mutex
上的锁定的时间比其他Workers
长得多。有时,其他两个Workers
只是互相交换,第三个继续等待Mutex.WaitOne()
;我想,如果没有真正输入它,因为其他Workers
在获取锁定方面没有问题!
我已经尝试过什么
我尝试将Worker
Tasks
作为TaskCreateOptions.LongRunning
启动,但没有任何改变。我还尝试通过指定Tasks
使嵌套 Tasks
成为孩子 TaskCreateOpions.AttachedToParent
,认为它可能与 local相关队列和日程安排,但显然不是。
简化代码
以下是我的实际应用程序的简化代码。可悲的是,我不能在这个简单的例子重现这种情况:
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
答案 0 :(得分:0)
解决方案是使用new SempahoreSlim(1)
代替Mutex
(或简单lock
或Monitor
)。仅使用SemaphoreSlim
使Thread Scheduling
成为循环,因此没有制作一些主题/任务&#34;特殊&#34;关于其他线程。谢谢I3arnon。
如果有人可以评论为什么会这样,我会很感激。