C# 处理单个线程上多个线程的请求-.NET内核
抱歉,如果这个问题已经有了答案,但如果有,我在这个网站上找不到 首先-这个问题是针对.NET核心的(撰写本文时为v1.1.0) 我有一个第三方程序集,它只处理来自同一线程的请求。此程序集是RabbitMQ库以及可能相关或不相关的问题的详细信息。基本上,我有多个线程可以调用这个程序集,但是如果请求来自不同的线程,它就会抛出一个异常 所以,为了避免这个问题,我试图创建一个被阻塞的线程,这样它就不会过期,并且必须在这个线程上处理对这个程序集的所有调用 我的第一次尝试是在被阻止的线程上创建一个事件并订阅该事件。然后,任何其他线程都会开始调用此事件,我认为可以在正确的线程上获取此事件,这样我就可以实现在单个线程上处理第三方程序集请求的愿望 我现在(痛苦地)明白:( 演示问题的示例:C# 处理单个线程上多个线程的请求-.NET内核,c#,multithreading,.net-core,C#,Multithreading,.net Core,抱歉,如果这个问题已经有了答案,但如果有,我在这个网站上找不到 首先-这个问题是针对.NET核心的(撰写本文时为v1.1.0) 我有一个第三方程序集,它只处理来自同一线程的请求。此程序集是RabbitMQ库以及可能相关或不相关的问题的详细信息。基本上,我有多个线程可以调用这个程序集,但是如果请求来自不同的线程,它就会抛出一个异常 所以,为了避免这个问题,我试图创建一个被阻塞的线程,这样它就不会过期,并且必须在这个线程上处理对这个程序集的所有调用 我的第一次尝试是在被阻止的线程上创建一个事件并订阅
public class Program
{
public static void Main(string[] args)
{
Program program = new Program();
ManualResetEvent resetEvent = new ManualResetEvent(false);
program.StartNewThreadToBeCalled(resetEvent);
program.CallBobMultipleTimes(resetEvent);
Console.ReadLine();
}
private void CallBobMultipleTimes(ManualResetEvent resetEvent)
{
resetEvent.WaitOne();
for(int i=0 ; i<100 ; i++)
ThreadPool.QueueUserWorkItem(x=>CallBob(null, null)); //Can't BeginInvoke in .NET Core
}
private void StartNewThreadToBeCalled(ManualResetEvent resetEvent)
{
ThreadPool.QueueUserWorkItem(x=>
{
Bob bob = new Bob();
CallBob += (obj, e)=> bob.InvokeMeOnOneThreadOnly();
resetEvent.Set();
ManualResetEvent mre = new ManualResetEvent(false);
mre.WaitOne(); //Real implementation will block forever - this should be the only thread handles the processing of requests.
});
}
public event EventHandler CallBob;
}
public class Bob
{
private List<int> ThreadIdentifiers = new List<int>();
private static object SyncObject = new object();
public void InvokeMeOnOneThreadOnly()
{
lock(SyncObject)
{
int currentThreadId = Thread.CurrentThread.ManagedThreadId;
if(ThreadIdentifiers.Any())
{
if(!ThreadIdentifiers.Contains(currentThreadId))
Console.WriteLine("Don't call me from multiple threads!");
}
else
ThreadIdentifiers.Add(currentThreadId);
}
}
}
公共类程序
{
公共静态void Main(字符串[]args)
{
程序=新程序();
ManualResetEvent resetEvent=新的ManualResetEvent(错误);
program.StartNewThreadToBeCalled(重置事件);
program.CallBobMultipleTimes(重置事件);
Console.ReadLine();
}
私有无效CallBobMultipleTimes(手动重置事件重置事件)
{
resetEvent.WaitOne();
for(int i=0;iCallBob(null,null));//无法在.NET核心中启动
}
私有void StartNewThreadToBeCalled(手动重置事件重置事件)
{
ThreadPool.QueueUserWorkItem(x=>
{
鲍勃=新鲍勃();
CallBob+=(obj,e)=>bob.invokeMeonneThreadOnly();
resetEvent.Set();
ManualResetEvent mre=新的ManualResetEvent(错误);
mre.WaitOne();//真正的实现将永远阻塞-这应该是处理请求的唯一线程。
});
}
公共事件处理程序CallBob;
}
公开课鲍勃
{
私有列表ThreadIdentifiers=新列表();
私有静态对象SyncObject=新对象();
public void invokeMeonneThreadOnly()
{
锁定(同步对象)
{
int currentThreadId=Thread.CurrentThread.ManagedThreadId;
if(ThreadIdentifiers.Any())
{
如果(!ThreadIdentifiers.Contains(currentThreadId))
WriteLine(“不要从多个线程中调用我!”);
}
其他的
ThreadIdentifiers.Add(currentThreadId);
}
}
}
我通过在concurrentQueue周围创建一个包装器来实现这一点,该包装器会在任何时候向concurrentQueue添加内容时发出通知。然后,我会在我的特殊第三方程序集线程上处理此事件,并从该队列中拾取请求,直到其耗尽为止……不确定为什么这样做会奏效,而另一种方式则不会
有没有比我找到的更好的方法对于我来说,在.NET core的单个线程上处理来自多个不同线程的多个请求?委托
BeginInvoke
使用threadpool
来调度回调
,这基本上是多个产品的生产者-消费者
问题CER和一个消费者..NET核心包括工具
IProducerConsumerCollection
可用于解决此问题
不要与控件.BeginInvoke
(winform)和调度程序.BeginInvoke
(WPF)混淆,它在GUI线程上对回调进行排队。委托使用threadpool
调度回调
,这基本上是一个生产者-消费者
问题,有多个生产者和一个消费者。.NET核心包括实现
IProducerConsumerCollection
可用于解决此问题
不要与控件.BeginInvoke
(winform)和调度程序.BeginInvoke
(WPF)混淆,将GUI线程上的回调排队。很难从代码中看出您正在尝试执行的操作。但是,另一种方法是使用BlockingCollection
。后台线程可以向该集合添加值,单个线程可以坐下来尝试从集合中获取值,例如:
while(continueProcessingCollection)
{
if(blockingCollection.TryTake(out value, TimeSpan.FromSeconds(myTimeout)))
{
// process value, decide to toggle continueProcessingCollection
}
}
后台线程可以向阻止集合添加新值:
blockingCollection.Add(newValue);
并且,您需要在某个地方创建blockingCollection变量:
var blockingCollection = new BlockingCollection<MyType>();
var blockingCollection=new blockingCollection();
很难从代码中看出您想要做什么。但是,另一种方法是使用BlockingCollection
。后台线程可以向该集合添加值,单个线程可以坐下来尝试从集合中获取值,例如:
while(continueProcessingCollection)
{
if(blockingCollection.TryTake(out value, TimeSpan.FromSeconds(myTimeout)))
{
// process value, decide to toggle continueProcessingCollection
}
}
后台线程可以向阻止集合添加新值:
blockingCollection.Add(newValue);
并且,您需要在某个地方创建blockingCollection变量:
var blockingCollection = new BlockingCollection<MyType>();
var blockingCollection=new blockingCollection();
由于队列是消费者-生产者模式的标准实现,因此,让它正常工作也就不足为奇了……没有办法知道为什么“其他方式”不起作用,因为对“其他方式”没有明确的解释(“通过创建代理”不是其中之一)。如果您需要答案,您需要澄清您为“其他方式”尝试了什么或者解释一下您希望以何种方式改进队列解决方案-在当前状态下,帖子感觉太宽泛了。@Alexei我发布帖子时正要下班-所以我没有时间获得更详细的帖子,我将尝试体验一下