希望有人能帮我正确设计。
在我的TCP代码中,我有一个尝试写入线路的SendMessage()函数。我正在尝试设计调用,以便在发生大量并发请求时将其移至生产者/消费者模型,但同时,如果没有并发请求(为了获得最佳性能),则保持单线程。
我正在努力研究如何在没有竞争条件的情况下进行设计,因为没有办法在线程之间移动锁。
到目前为止我所拥有的是(伪编码):
SendMessage(msg) {
if(Monitor.TryEnter(wirelock,200)) {
try{
sendBytes(msg);
}
finally {
Monitor.Exit...
}
}
else {
_SomeThreadSafeQueue.add(msg)
Monitor.TryEnter(consumerlock,..
Task.Factory.New(ConsumerThreadMethod....
}
}
ConsumerThreadMethod() {
lock (wirelock) {
while(therearemessagesinthequeue)
sendBytes...
}
}
任何明显的竞争条件?
编辑:发现最后一个漏洞。怎么样呢?SendMessage(msg) {
if(Monitor.TryEnter(wirelock)) {
try{
sendBytes(msg);
}
finally {
Monitor.Exit...
}
}
else {
_SomeThreadSafeQueue.add(msg)
if (Interlocked.Increment(ref _threadcounter) == 1)
{
Task.Factory.StartNew(() => ConsumerThreadMethod());
}
else
{
Interlocked.Decrement(ref _threadcounter);
}
}
}
ConsumerThreadMethod() {
while(therearemessagesinthequeue)
lock (wirelock) {
sendBytes...
}
}
Interlocked.Decrement(ref _threadcounter);
}
所以基本上使用互锁计数器作为只生成一个线程(如果需要)的方法
答案 0 :(得分:0)
没有明显的比赛,但TryEnter导致一些严重的空闲时间。我实际上认为一直使用消费者线程是最好的解决方案。如果没有什么可做的,开销将非常小(如果设计不正确,消费者线程将在不工作时睡着)。
现在,您为每个已发送的消息创建一个新任务,从而导致对锁的巨大争用,因为您在使用者线程中使用了while循环。
编辑:由于您使用的是非阻塞套接字,因此单个使用者线程应足以处理所有发送请求。单个线程的吞吐量高于您的网络。如果你有更多的消费者,很难确保没有两个消费者线程在同一个套接字上发送,而没有使用互斥锁序列化所有内容。我不认为在单线程和多线程之间切换是个好主意。
您当前的“多线程”解决方案不会给您带来任何性能提升,因为所有工作都使用相同的互斥锁进行保护。它将比单个线程慢或慢。