如何在WinForms中测试[STAThread]的性能影响? [英] How do I test performance impact of [STAThread] in WinForms?

查看:113
本文介绍了如何在WinForms中测试[STAThread]的性能影响?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我设法用C#编写了一个相对较大的WinForms应用程序,该应用程序在 Main() [STAThread] 属性的情况下可以正常运行c $ c>方法。



要实现此目的,我必须重写许多WinForms功能(例如使用自定义的 BeginInvoke Invoke 函数),使用自定义消息循环而不是 Application.Run ,使用自定义文件对话框而不是 OpenFileDialog SaveFileDialog ,然后使用 WM_DROPFILES 用于拖放而不是WinForms的即用OLE方法。这都是为了科学。



现在,我想测试省略 STAThreadAttribute 来自所有GUI线程。我对 Control 类,以能够预测此类影响。执行速度可能取决于哪个线程正在调用 Control 的内部COM对象。



诚然,我是很难找到一个基准来测试与 [STAThread] 有关的性能影响,因为我不确定哪些功能/操作会受到这种更改的影响(具体来说与 Control 类有关。



我应该确切地寻找什么?我应该通过省略 [STAThread] (如果有)来期望 Control 类中的哪些操作/方法运行更快/更慢?



附录:理由是,我正在慢慢迁移应用程序以使用自定义窗口系统(出于可移植性的原因,主要是为了在Linux上使用Mono(其WinForms实现尚未完成),因此无论如何我都不得不重写许多功能。只是巧合,我注意到我已经重写了太多的功能,可以忽略[STAThread],并且一切仍然可以按预期进行。



我希望由于来自 ThreadPool (配置为MTA)和GUI线程(默认情况下应配置为STA)的COM封送处理调用而导致的性能下降。从 ThreadPool 到GUI线程的调用将需要进行编组,因为它们是在不同的线程单元中配置的,这会带来同步开销。通过将GUI线程保留为MTA,应减少编组,从而可能更快地执行函数调用。我想以务实的方式对此要求进行检验。

解决方案

[STAThread]具有太多的神秘色彩。但是实际上很简单,您要做一个 promise 。跨过你的心,希望死。您向操作系统保证,主线程是线程安全的好地方。遵守承诺要求拥有调度程序(Application.Run),并且永远不要阻塞线程。



在Windows上运行的GUI应用程序中,总是会有很多这样的代码。无论使用哪种框架,此类代码的位置都更加明显。但是,最糟糕的是您看不到的代码。在外壳扩展,UI自动化代码中,希望通过剪贴板或拖放操作提供数据的应用中,SetWindowsHookEx附带的挂钩中,视力不佳的用户的屏幕阅读器中,期望PostMessage的ActiveX组件中都存在这种类型去工作。这样的代码不必是线程安全的,操作系统并不需要它,主要是因为编写该代码的人无法对其进行测试。他不了解您的应用程序。



这对操作系统很重要,因为在上运行此类代码时,它必须执行某些操作UI线程。由于代码明确声明了它不是线程安全的或不一定是线程安全的,因此无论如何都必须确保代码安全。唯一可行的方法是初始化代码并在同一线程上对其进行任何将来的调用。这需要一些技巧,必须对代码进行编组,使其可以在另一个线程上运行,而调度程序循环对于完成此工作至关重要。调度员是生产者-消费者问题的通用解决方案。。 p>

但是,如果代码是从正确的线程初始化的,则没有必要。操作系统如何知道它是否是正确的线程?



因此,您可以得出的第一个结论是不将UI线程标记为STA实际上使您的程序变慢了。 。由于每个电话都被编组。这不是唯一的问题,有很多这样的代码无法编组。作者必须做额外的工作才能启用它,他必须提供代理/存根。有时候这太难了,但他却根本没有这么做,因为他依靠你来正确地做。因此,通话将失败。但这是在外部代码中发生的,您不会找到。所以东西根本不起作用。或僵局。否则不会引发预期的事件。惨的东西。您必须使用[STAThread]来避免痛苦。



这是纯Windows实现的详细信息,在Unixes上不存在。他们提供这些功能的方式完全不同(如果有的话)。因此,[STAThread]并不意味着在这样的操作系统上有任何意义,并且测试没有它的情况不会告诉您任何事情。


I managed to write a relatively large WinForms application in C# that functions correctly without the [STAThread] attribute on the Main() method.

To accomplish this I had to override a lot of WinForms functionality (such as using a custom BeginInvoke and Invoke functions), use a custom message loop instead of Application.Run, use a custom file dialog instead of OpenFileDialog and SaveFileDialog, and use WM_DROPFILES for drag-and-drop instead of the WinForms out-of-the-box OLE approach. This is all "for science".

Now I want to test for any possible performance impact of omitting the STAThreadAttribute from all GUI threads. I do not possess deep enough knowledge of the COM configuration used internally by the Control class to be able to predict such impact. Speed of execution probably depends on which thread is calling the internal COM object of the Control.

Admittedly, I am having trouble coming up with a benchmark that would test for performance impact pertaining to [STAThread], because I am unsure of which functions/operations would be affected by such a change (specifically related to the Control class).

What should I look for exactly? Which operations/methods from the Control class should I expect to run faster/slower by omitting [STAThread], if any?

Addendum: The rationale is that I am slowly migrating my application to use a custom windowing system (for portability reasons, mainly for using Mono on Linux, whose WinForms implementation is not complete), so I had to override a lot of functionality myself anyway. It was merely a coincidence that I noticed that I had overridden so much functionality that I could omit [STAThread] and everything would still work as expected.

I expect a change in performance due to COM marshaling calls from the ThreadPool (which is configured as MTA), and the GUI thread (which by default should be configured as STA). Calls from the ThreadPool to the GUI thread would need to be marshalled due to them being configured in different thread apartments, which introduces a synchronization overhead. By leaving the GUI thread as MTA, the marshalling should be reduced, hence possibly faster execution of function calls. I would like to test this claim pragmatically.

解决方案

[STAThread] has too much mystique attached. But in practice is very simple, you make a promise. Cross your heart, hope to die. You promise to the OS that your main thread is a hospitable home for code that is not thread-safe. Keeping the promise requires having a dispatcher (Application.Run) and never blocking the thread. Things you do later, that's why you have to make the promise up front.

In a GUI app that runs on Windows there is always a lot of that code around. Whatever framework you use is the more obvious place for such code. But the far nastier stuff is the code you cannot see. The kind that lives inside shell extensions, in UI Automation code, in apps that want to provide data through the clipboard or drag+drop, in hooks installed with SetWindowsHookEx, in screen-readers for users with visual impairments, in ActiveX components that expect PostMessage to work. Such code doesn't have to be thread-safe, the OS does not demand that it is, mostly because whomever wrote that code has no way to test it. He didn't know beans about your app.

It matters to the OS because it has to do something when such code does not run on the UI thread. Since the code explicitly announces that it is not thread-safe, or doesn't have to be, it has to keep the code safe anyway. Only way that is possible is by initializing the code and make any future calls to it on the same thread. That requires some trickery, the code has to be marshalled, made to run on another thread, having a dispatcher loop is crucial to make that work. A dispatcher is the universal solution to the producer-consumer problem.

But if the code is initialized from the right thread then this is not necessary. How does the OS know whether it is the "right thread"? The [STAThread] promise tells it that.

So first conclusion you can make is not marking the UI thread as STA actually makes your program slower. Since every call is marshalled. Not the only problem, there is a lot of such code that cannot be marshalled. The author has to do extra work to enable it, he has to provide a proxy/stub. Sometimes it is just too hard, often he simply doesn't since he relies on you doing it right. So the call will fail miserably. But this happens in external code, you won't find out. So stuff just doesn't work. Or deadlocks. Or an expected event doesn't get raised. Miserable stuff. You must use [STAThread] to avoid the misery.

This is otherwise a pure Windows implementation detail, it does not exist on the Unixes. They have just completely different ways to provide these features, if at all. So [STAThread] does not mean anything on such an OS and testing what happens without it doesn't tell you anything.

这篇关于如何在WinForms中测试[STAThread]的性能影响?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆