如何调试 .NET 远程调用?
我有一个具有以下基本架构的应用程序:
注册 .NET 类型 (RemoteObject) 以进行远程访问 (.NET Remoting) 的 Windows 服务 (Service)。 RemoteObject 创建非 ThreadPool 线程,使用 ThreadPool 进行 IO 处理。 由于特定原因,必须将线程池的大小限制在某个限度内。 GUI 应用程序使用 .NET Remoting 来访问 RemoteObject。
我注意到,如果 ThreadPool 的大小太小,GUI 应用程序在调用 RemoteObject 时将会挂起。
我的问题是,如何找出挂起的原因,以及为什么 RemoteObject 线程会受到 ThreadPool 的影响?
这真让我抓狂; 感谢您的帮助!
I have an app with the following basic architecture:
A windows service (Service) that registers a .NET type (RemoteObject) for remote access (.NET Remoting). RemoteObject creates non-ThreadPool threads that use the ThreadPool to do IO processing. The size of the ThreadPool must be restricted to a limit for a particular reason. A GUI app uses .NET Remoting to access RemoteObject.
I've noticed that if the size of the ThreadPool is too low, the GUI app will hang when making a call to RemoteObject.
My question is, how can I figure out why this is hanging, and why would the RemoteObject thread be affected by the ThreadPool?
This is driving me crazy; thank you for your help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不确定这是否有帮助(我无法判断这是否是您的问题),但是如果您想在服务运行时对其进行调试,您可以将其添加到代码中:
然后您会得到一个对话框要求您选择调试器。 这是附加到正在运行的服务实例的简单方法。 如果不出意外,这将让您在 UI 挂起时(通过按调试工具栏上的暂停按钮)闯入您的服务并检查您的线程和调用堆栈。
I'm not sure if this will help (I can't tell if this is your problem or not), but if you want to debug your service as its running, you can slap this in your code:
and you'll get a dialog asking you to select a debugger. Its an easy way to attach to a running instance of a service. If nothing else, this will let you break into your service when the UI is hanging (by pressing the pause button on your debug toolbar) and check out your threads and callstack.
事实证明,.NET 远程处理基础结构使用 .NET ThreadPool(或共享底层资源),因此如果您的应用程序正在使用所有 ThreadPool 线程,则远程调用可能会挂起。
It turns out that the .NET remoting infrastructure uses the .NET ThreadPool (or shares the underlying resource), so remoting calls can hang if all ThreadPool threads are in use by your app.
这可能不是特别有帮助,但无论如何我都会把它扔掉。
当调试通过远程处理进行通信的服务和客户端时,我通常会运行调试器的两个实例:一个用于客户端,一个用于服务。 需要明确的是,我正在运行两个 Visual Studio 副本。 对于服务,您可以使用 Attach 命令,也可以更改 main 并直接调用启动(绕过所有服务代码)。
以下是我通常如何通过更改 main 来启用调试,您必须更改 main 以及对服务的 DebugService 调用,它实际上只是调用 start 的入口点。 一旦我有了这个,我只需通过定义
SERVICE_DEBUG
或通过添加“!”
更改#if
来启用服务调试。 现在您基本上已将服务转换为控制台应用程序。一旦完成设置并运行,您就可以单步执行客户端,当远程调用命中服务时,您可以单步执行服务代码,从而允许您同时调试两者。
出于好奇您是否直接从 GUI 线程调用远程对象? 如果是这样,GUI 线程将阻塞,直到远程调用完成。 这将锁定整个 GUI 并使其无响应。 这不是问题的解决方案,但如果是这种情况并且您的服务线程没有返回,它也会导致 GUI 挂起。
This may not be exceptionally helpful but I will toss it out there anyways.
When debugging services and clients that talk through remoting, I will usually always run two instances of the debugger: one for the client and one for the service. Just to be clear, I am running two copies of visual studio. For the service you can use the attach command or you can alter the main and call start directly (bypassing all the service code).
Here is how I typically enable debugging by altering the main, you'll have to and the DebugService call to the service, it really is just a entry point that calls start. Once I have this I just enable service debug by definine
SERVICE_DEBUG
or changing the#if
by adding a '!'
. Now you basically have converted your service to a console app.Once you have both setup and running you can step through the client, when the remoting calls hit the service you can step through the service code, allowing you to debug both at the same time.
Out of curiosity are you calling the remote object directly from the GUI thread? If so, the GUI thread will block until the remoting call completes. This will lock up the whole GUI and make it unresponsive. This isn't the solution to the problem, but if it is the case and your service thread isn't returning, it'll cause the GUI to hang as well.
几年前,我设计并实现了一个使用 .NET Remoting 的关键业务系统。 我们有一个作为 Windows 窗体 GUI 实现的客户端、一个作为 Windows 服务实现的服务器和一个 SQL Server 数据库。
我是为故障排除/调试/开发而设计的,因此我的首要设计标准之一是我可以轻松删除整个 .NET Remoting 实现并在桌面上运行整个系统。 因此,我可以通过将单个布尔配置设置更改为“false”= off 来停用远程处理。 然后,我可以完全排除故障、调试和开发,而无需 .NET Remoting 的开销或干扰。
看来这对您的情况也很有价值。 事实上,我无法想象在什么情况下这不是一个理想的功能,特别是因为它很容易实现。
因此,为了实现它,每个客户端和服务器代码都使用配置设置来决定实例化哪个实现类以与另一端进行通信。 所有通信都通过自定义 C# 接口进行,该接口的每一侧都有两个具体的实现类:一个类使用 .NET Remoting 实现通信,另一个类将通信实现为直接进程内直通(直接调用)。
只有一对类(每一侧各一个)了解 .NET Remoting,因此完全隔离。 大多数时候,所有开发人员都在关闭远程处理的情况下工作,这样更快、更简单。 当他们需要时,在极少数情况下,他们会打开它(大多数情况下只有我,或者当有人连接到测试/生产进行故障排除时)。
顺便说一句,我使远程接口非常简单:
public Responseexecute(Request)
除此之外,我还使用了上面提到的调试器启动技巧,并且我同意您需要注意对 GUI 线程的影响。
A few years ago, I designed and implemented a critical business system that used .NET Remoting. We had a client implemented as a Windows Forms GUI, a server implemented as a Windows Service, and a SQL Server database.
I designed for troubleshooting/debugging/development, so one of my first design criteria was that I could trivially remove the entire .NET Remoting implementation and run the whole system on my desktop. So, I could deactivate the remoting by changing a single boolean configuration setting to "false" = off. I could then troubleshoot, debug, develop completely without the overhead or interference of .NET Remoting.
It seems that this would be valuable for your situation as well. As a matter of fact, I can't imagine a situation in which that is not a desirable feature, especially since it is easy to implement.
So, to implement it, the configuration setting was used by each of the client and the server code to decide which implementation class to instantiate for communication with the other side. All communication occurred through a custom C# interface which had two concrete implementation classes on each side: one class implemented the communication using .NET Remoting, the other class implemented the communication as a direct in-process passthrough (direct calls).
Only the one pair of classes (one on each side) knew anything about .NET Remoting, so the isolation was total. Most of the time, all the developers worked with the remoting turned off, which was faster and simpler. When they needed to, on rare occasion, they turned it on (mostly just me, or when someone connected to test/production for troubleshooting).
By the way, I made the remoting interface dead simple:
public Response execute(Request)
Beyond that, I also used the debugger launching tip mentioned above, and I agree that you need to be mindful of the impact to the GUI threading.