这是我的Web服务服务器端和客户端示例程序。我遇到了一个strnage性能问题,即使我增加调用Web服务的线程数,性能也没有提高。同时,任务管理器性能面板的CPU /内存/网络消耗很低。我想知道瓶颈是什么以及如何改进它?
(我的测试经验,线程数增加一倍,总响应时间几乎翻倍)
客户方:
class Program
{
static Service1[] clients = null;
static Thread[] threads = null;
static void ThreadJob (object index)
{
// query 1000 times
for (int i = 0; i < 100; i++)
{
clients[(int)index].HelloWorld();
}
}
static void Main(string[] args)
{
Console.WriteLine("Specify number of threads: ");
int number = Int32.Parse(Console.ReadLine());
clients = new Service1[number];
threads = new Thread[number];
for (int i = 0; i < number; i++)
{
clients [i] = new Service1();
ParameterizedThreadStart starter = new ParameterizedThreadStart(ThreadJob);
threads[i] = new Thread(starter);
}
DateTime begin = DateTime.Now;
for (int i = 0; i < number; i++)
{
threads[i].Start(i);
}
for (int i = 0; i < number; i++)
{
threads[i].Join();
}
Console.WriteLine("Total elapsed time (s): " + (DateTime.Now - begin).TotalSeconds);
return;
}
}
服务器端:
[WebMethod]
public double HelloWorld()
{
return new Random().NextDouble();
}
提前谢谢,
乔治
答案 0 :(得分:7)
虽然您正在创建多线程客户端,但请记住,.NET具有可配置的瓶颈,可同时调用2个单个主机。这是设计的。 请注意,这是在客户端,而不是服务器上。
尝试在客户端调整app.config文件:
<system.net>
<connectionManagement>
<add address=“*” maxconnection=“20″ />
</connectionManagement></system.net>
this short article中有更多相关信息:
答案 1 :(得分:5)
我的经验通常是锁定是问题:我有一个大规模并行服务器,一次花费更多时间上下文切换而不是执行工作。
所以 - 检查你的内存并在perfmon中处理计数器,如果你看一下上下文切换及其高(每秒超过4000),那么你就麻烦了。
您也可以检查服务器上的内存统计信息 - 如果它花费所有时间交换,或者只是创建和释放字符串,它似乎也会停止。
最后,检查磁盘I / O,原因与上面相同。
解决方法是移除锁定,或保持锁定至少一段时间。通过消除对COM BSTR及其全局锁的依赖来解决我们的问题,你会发现C#有很多类似的同步瓶颈(旨在保证你的代码安全运行)。当我将一个简单的C#应用程序从单核移动到多核盒时,我已经看到性能下降。
如果你无法删除锁,那么最好的选择就是不要创建尽可能多的线程:)使用线程池代替让CPU在完成另一个工作之前完成一个工作。
答案 2 :(得分:3)
我不相信你实际上遇到了瓶颈。
你尝试过我的建议吗?
您的想法是添加更多线程来提高性能,因为您期望所有线程都能并行完美运行。这就是为什么你假设线程数加倍不应该使总测试时间加倍。
您的服务需要几分之一秒的时间才能返回,并且您的线程不会全部在客户端的同一时刻开始工作。
所以你的线程并没有像你想象的那样完全并行工作,你所看到的结果是可以预期的。
答案 3 :(得分:2)
您没有看到任何性能提升,因为没有。无论如何,您的服务中的一行代码(下面)可能在大多数时间没有上下文切换的情况下执行。
return new Random().NextDouble();
Web服务调用涉及的开销高于您在其中进行的工作。如果您在服务中有一些实质性工作(数据库调用,查找,文件访问等),您可能会开始看到一些性能提升。 只是并行化任务不会自动使其更快。
-Jason
答案 4 :(得分:1)
当然,添加睡眠不会提高性能。
但测试的重点是使用可变数量的线程进行测试。 因此,请将Sleep保留在WebMethod中。
现在尝试5,10,20个线程。
如果您的代码没有其他问题,那么时间的增加不应像以前那样是线性的。
您意识到,在您的测试中,当您将线程数量增加一倍时,您正在将正在完成的工作量增加一倍。因此,如果你的线程没有真正并行执行,那么你当然会看到总时间的线性增长......
我使用您的客户端代码运行了一个简单的测试(在服务上休眠)。 对于5个线程,我看到总时间约为53秒。 对于10个线程,62秒。 因此,对于2次调用Web服务的次数,它只花了17%的时间..这就是你所期待的,不是吗?
答案 5 :(得分:0)
嗯,在这种情况下,你并没有真正平衡你选择的线程之间的工作......你创建的每个线程都将执行相同的工作。因此,如果您创建n个线程并且您具有有限的并行处理能力,则性能自然会降低。另一个想法我注意到,所需的Job是100次迭代的相对快速的操作,即使你打算通过多个线程划分这个Job,你需要考虑在上下文切换中花费的时间,线程创建/删除将是一个重要因素在整个时间里。
答案 6 :(得分:0)
正如布鲁诺所说,你的网络方法是一个非常快速的操作。作为实验,请尝试确保HelloWorld方法需要更长时间。在返回随机双精度之前抛出Thread.Sleep(1000)。这将使您的服务更有可能被迫并行处理请求。 然后尝试使用不同线程数量的客户端,并查看性能如何不同。
答案 7 :(得分:0)
尝试使用一些处理器消耗任务而不是Thread.Sleep。实际上,组合方法是最好的。
Sleep只会将线程的时间帧传递给另一个线程。
答案 8 :(得分:0)
IIS AppPool&#34;最大工作进程&#34;默认设置为1。出于某种原因,每个工作进程限制为一次处理10个服务调用。我的WCF异步服务器端功能执行睡眠(10 * 1000);只要。 当Maximum Worker Processes = 1时会发生这种情况 http://s4.postimg.org/4qc26cc65/image.png
替代地
http://i.imgur.com/C5FPbpQ.png?1
(关于SO的第一篇文章,我需要将所有图片合并为一张图片。)
客户端在此测试中正在进行48次异步WCF WS调用(使用16个进程)。理想情况下,这需要大约10秒才能完成(睡眠(10000)),但需要52秒。您可以在perfmon图片中看到5条水平线(上面的链接)(使用perfmon监视服务器中的Web Service Current Connections)。每条水平线持续10秒(睡眠(10000))。有5条水平线,因为服务器每次处理10个呼叫然后关闭10个连接(这发生5次以处理48个呼叫)。完成所有通话需要52秒。
设置最大工作进程数= 2 (在上面给出的相同图片中) 这次有3条水平线,因为服务器每次处理20个呼叫然后关闭那20个连接(这发生3次以处理48个呼叫)。花了33秒。
设置最大工作进程数= 3 (在上面给出的相同图片中) 这次有2条水平线,因为服务器每次处理30个呼叫。 (发生2次处理48次通话)花了24秒。
设置最大工作进程数= 8 (在上面给出的相同图片中) 这次有一条水平线,因为服务器每次处理80个呼叫。 (发生一次处理48个电话)花了14秒。
如果您不关心这种情况,您的并行(异步或线程)客户端调用将在服务器中排队10秒,然后所有线程调用(&gt; 10)都不会被处理由服务器并行。
PS:我使用的是Windows 8 x64和IIS 8.5。 10个并发请求限制适用于工作站Windows操作系统。服务器操作系统根据SO上的另一个帖子没有限制(由于rep&lt; 10,我无法提供链接)。