有没有人试图找出 - 什么是更快,什么更有效(创建的对象更少,因此涉及的GC更少) - control.BeginInvoke或SynchroniseContext.Post?
WPF,C#,.NET 4
我很欣赏以实际支持而非“我认为”或“我在某处听到”的回应。
干杯
P.S。我将向一些控件发布一些消息,我希望它能够最快速有效(几百次更新/秒)。我知道.NET可以处理这个问题(我之前做过),但现在我想让它尽快 ......
答案 0 :(得分:4)
首先,WPF中没有Control.BeginInvoke
(这是你想到的winforms)。其次,SynchronizationContext
是对当前平台提供的任何同步机制的抽象。在WPF的情况下,它是Dispatcher
的抽象。从理论上讲,你为使用抽象而不是直接使用Dispatcher
付出了很小的代价。但抽象是有充分理由的 - 有时您需要编写独立于平台的线程同步代码。如果不这样做,请务必直接使用Dispatcher
。
答案 1 :(得分:2)
我的i7桌面上的BeginInvoke比SynchronizationContext.Post快42.8%。
结果是:
Post Send Diff ms Ratio
1280866 925416 35.00 -38.4%
1192232 916251 27.00 -30.1%
1338990 876215 46.00 -52.8%
1394783 863241 53.00 -61.6%
1332485 1046789 28.00 -27.3%
1335241 895784 43.00 -49.1%
1267470 1064894 20.00 -19.0%
1308461 884136 42.00 -48.0%
1321243 850704 47.00 -55.3%
1313230 896469 41.00 -46.5%
代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
}
Thread th;
DispatcherSynchronizationContext ctx;
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
Thread.CurrentThread.Priority = ThreadPriority.Highest;
ctx = new DispatcherSynchronizationContext(this.Dispatcher);
th = new Thread(Start);
th.Start();
}
int MACRO = 10;
int TESTS = 10;
int LOOPS = 50000;
void Start()
{
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
// flush just in case
for (int i = 0; i < 100; i++)
{
ctx.Post(Callback, 9999999);
this.Dispatcher.BeginInvoke(
new Action<object>((object state) => { txt2.Text = state.ToString(); }),
DispatcherPriority.Send, 9999999);
}
Thread.Sleep(1000);
// results
List<Tuple<long, long>> results = new List<Tuple<long, long>>();
// actual test
for (int x = 0; x < MACRO; x++)
{
Stopwatch sw = new Stopwatch();
// sync context post
long tick1, tick2;
for (int i = 0; i < TESTS; i++)
{
sw.Start();
for (int j = i; j < LOOPS + i; j++)
{
ctx.Post(Callback, j);
}
sw.Stop();
Thread.Sleep(1500);
}
tick1 = sw.ElapsedTicks;
// begin invoke
sw.Reset();
for (int i = 0; i < TESTS; i++)
{
sw.Start();
for (int j = i; j < LOOPS + i; j++)
{
this.Dispatcher.BeginInvoke(
new Action<object>((object state) => { txt2.Text = state.ToString(); }),
DispatcherPriority.Normal, j);
}
sw.Stop();
Thread.Sleep(1500);
}
tick2 = sw.ElapsedTicks;
// store results
results.Add(new Tuple<long, long>(tick1, tick2));
// display to make it less boring
this.Dispatcher.BeginInvoke(new Action(() => { txt3.Text += string.Format("{0} {1}. ", tick1, tick2); }));
Thread.Sleep(100);
}
StringBuilder sb = new StringBuilder();
foreach (var res in results)
sb.AppendLine(string.Format("{0}\t{1}\t{2:0.00}\t{3:0.0%}",
res.Item1, res.Item2, (res.Item1 - res.Item2) / 10000, res.Item2 != 0 ? 1.0 - res.Item1 / (double)res.Item2 : 0.0));
this.Dispatcher.BeginInvoke(
new Action(() => { txb1.Text = sb.ToString(); }));
}
void Callback(object state)
{
txt1.Text = state.ToString();
}
}