【发布时间】:2011-09-15 20:13:28
【问题描述】:
谁能告诉我为什么其中一种 DoCalculation 方法比另一种快得多(比如快 40%)?
我有等待设置 ManualResetEvents 的主线程:
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem((obj) =>
{
ManualResetEvent[] finishcalc = new ManualResetEvent[]
{
new ManualResetEvent(false),
new ManualResetEvent(false),
new ManualResetEvent(false),
new ManualResetEvent(false),
new ManualResetEvent(false),
new ManualResetEvent(false)
};
TimeSpan time1 = new TimeSpan(DateTime.Now.Ticks);
DoCalculation(rand.Next(10), rand.Next(10), 1, finishcalc[0]);
DoCalculation(rand.Next(10), rand.Next(10), 2, finishcalc[1]);
DoCalculation(rand.Next(10), rand.Next(10), 3, finishcalc[2]);
DoCalculation(rand.Next(10), rand.Next(10), 4, finishcalc[3]);
DoCalculation(rand.Next(10), rand.Next(10), 5, finishcalc[4]);
DoCalculation(rand.Next(10), rand.Next(10), 6, finishcalc[5]);
if (WaitHandle.WaitAll(finishcalc))
{
TimeSpan time2 =new TimeSpan(DateTime.Now.Ticks);
AddTextAsync(string.Format("DoCalculation Finish in {0}\n" ,(time2-time1).TotalSeconds));
}
});
}
然后我有一个方法,它创建另一个线程来按顺序进行一些计算,也就是说,我需要前一个线程的结果来继续下一个。我找到了两种方法,这是针对 Silverlight 的。
在第一个示例中,我正在创建一个新线程,它会等待每个连续计算完成后再继续:
void DoCalculation(int number1, int number2, int callid, ManualResetEvent calcdone)
{
ThreadPool.QueueUserWorkItem((obj0) =>
{
AddTextAsync(string.Format("The values for Callid {0} are {1} and {2}\n", callid, number1, number2));
int result = 0;
ManualResetEvent mresetevent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem((obj) =>
{
result = number1 + number2;
mresetevent.Set();
});
mresetevent.WaitOne();
mresetevent.Reset();
ThreadPool.QueueUserWorkItem((obj2) =>
{
result *= result;
mresetevent.Set();
});
mresetevent.WaitOne();
mresetevent.Reset();
ThreadPool.QueueUserWorkItem((obj2) =>
{
result *= 2;
mresetevent.Set();
});
mresetevent.WaitOne();
AddTextAsync(string.Format("The result for Callid {0} is {1} \n", callid, result));
calcdone.Set();
});
}
DoCalculation 的第二个例子我使用一个类作为链接,将一个 Action 作为参数传递给 ThreadPool,并使用它作为回调来创建链中的第二个和第三个线程:
链接类:
public class CalcParams
{
public int CallID;
public ManualResetEvent ManualReset;
public int Result;
public Action<int, ManualResetEvent, int> CallbackDone;
}
异步服务示例::
public static void DownloadDataInBackground(CalcParams calcparams)
{
WebClient client = new WebClient();
Uri uri = new Uri("http://www.google.com");
client.DownloadStringCompleted += (s, e) =>
{
CalcParams localparams = (CalcParams)e.UserState;
localparams.CallbackDone(e.Result.Length + localparams.Result, localparams.ManualReset, localparams.CallID);
};
client.DownloadStringAsync(uri, calcparams);
}
以及改进后的doCalculation方法:
void DoCalculation(int number1, int number2, int callid, ManualResetEvent calcdone)
{
ThreadPool.QueueUserWorkItem((obj0) =>
{
int result = number1+number2;
doCalculationService.DownloadDataInBackground(new CalcParams()
{
Result = result,
ManualReset = calcdone,
CallID = callid,
CallbackDone = (r, m, i) =>
{
int sqrt = r * r;
doCalculationService.DownloadDataInBackground(new CalcParams()
{
Result = sqrt,
CallID = i,
ManualReset = m,
CallbackDone = (r2, m2, i2) =>
{
int result2 = r2 * 2;
AddTextAsync(string.Format("The result for Callid {0} is {1} \n", i2, result2));
m2.Set();
}
});
}
});
});
}
谢谢。
【问题讨论】:
-
你可以用秒表来测量时间,只是为了兴趣,结果是否相同?你也可以分享一下 AddTextAsync 的代码,也许有瓶颈?
-
我相信秒表在 Silverlight 中不可用。我可以在其他平台上进行相同的测试,但现在我只对 silverlight 感兴趣。而且这两种方法之间的时间差异太大了,即使删除了额外的调用,我也不明白为什么......
-
我认为这是示例代码,其中有很多 QueueUserWorkItem。事实上,家政费用远远超过你所做的工作量。
-
您的新示例更加令人困惑。您正在调用
ThreadPool.QueueUserWorkItem来运行一个后台作业,该作业只是将 another 线程排队以在后台下载,然后链接到另一个类似的构造。总之,当你真的只需要一个线程时,你创建了 5 个线程,因为你的作业是按顺序执行的。您所拥有的与单个QueueUserWorkItem没有什么不同,其中包含对DownloadString的两次调用和一个按顺序执行的计算。 -
发布问题的基本理念是提供最少量的代码来说明问题。不要将所有变体和试验都转嫁给读者。
标签: c# multithreading silverlight performance