Reputation: 31
I am trying to understand why nancyFx in my sample project can't handle parallel queries. I am running Windows 8, VS2015, C#, fiddler 4.
Here is my sample service:
class Program
{
static void Main(string[] args)
{
Listen();
}
static void Listen()
{
using (var host = new NancyHost(new Uri("http://localhost:4546")))
{
host.Start();
Console.ReadLine();
}
}
}
public class TestModule : NancyModule
{
public TestModule() : base("/")
{
Get["/"] = (param) =>
{
Debug.WriteLine("Start:" + DateTime.Now.TimeOfDay.ToString());
Thread.Sleep(100);
Debug.WriteLine("End:" + DateTime.Now.TimeOfDay.ToString());
return Response.AsText("Success");
};
}
}
Here is the sample query:
GET http://localhost:4546/ HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: ru-RU
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: localhost:4546
Connection: Keep-Alive
I have used fiddler 4 for parallel query generation (Replay feature) and measure query running time.
When I am running one query - handling time is about 100ms(0:00:00.104),
But when I am running multiple queries - handling time grows too much, here is example:
Fiddler parallel queries screenshot
And Debug output:
Start:09:56:32.8385200
Start:09:56:32.8443855
End:09:56:32.9396601
End:09:56:32.9455256
Start:09:56:32.9465022
End:09:56:33.0478691
Start:09:56:33.0478691
End:09:56:33.1498256
Start:09:56:33.1507976
End:09:56:33.2516390
Start:09:56:33.2535998
End:09:56:33.3554522
Start:09:56:33.3564277
End:09:56:33.4584340
Start:09:56:33.4594080
End:09:56:33.5608216
Start:09:56:33.5617992
End:09:56:33.6631615
Start:09:56:33.6641370
End:09:56:33.7649969
Start:09:56:33.7659714
End:09:56:33.8673301
Start:09:56:33.8683072
End:09:56:33.9696905
Start:09:56:33.9706676
End:09:56:34.0713212
Start:09:56:34.0722972
End:09:56:34.1729940
Start:09:56:34.1759211
End:09:56:34.2774876
As we can see in fiddler timeline - all queries start running at same time, but have different execution time.
Also we can replace Thread.Sleep with different payload and behavior still the same.
Also we can replace fiddler with RestSharp, HttpClient for query generation - behavior still the same.
Also we can replace NancyFx with ServiceStack.Server (also self-hosted) - behavior still the same.
Why? :) And how I can fix it?
UPD: Also, by @FireAlkazar's guess i have tried to remove Debug.WriteLine's.
Now code is:
Get["/"] = (param) => {
var response = Response.AsText("");
Thread.Sleep(100);
return response;
};
And results are same, here is screenshot: here is it
Upvotes: 3
Views: 1463
Reputation: 3315
There is a bugfix in Nancy.Hosting.Self that addresses this issue. However, the latest preview NuGet package is 1.5 years old and does not contain this fix.
You can follow these steps to fix the bug without an update to the NuGet package:
MaximumConnectionCount
and ProcessorThreadCount
properties from HostConfiguration.cs file into your NancyHost
class.NancyHost
code to use copied properties instead of the ones in HostConfiguration
.NancyHost
class to start program.Upvotes: 1
Reputation: 1880
I guess it is Debug.WriteLine
calls causes this behavior.
Writing to console in a multithreaded environment will lock threads similiar to code
lock(globalStaticObject)
{
Print("some message")
}
Try to remove Debug.WriteLine calls and test again.
EDIT
I have the same code you provided and I can't reproduce the behavior.
My results are as expected.
I tried to changed the number of sleep milliseconds to 1000 - all the same.
Even adding Debug.WriteLine has no the effect that you have.
Maybe you have tested the site when your processor cores were under load?
Upvotes: 0
Reputation: 11
Have you guys tried to make the methods async? The true parameter tells Nancy to run as async, and the async keyword tells VS that the code within is going to return a Task or have an await keyword... Note I haven't tested this code, as I am using it in a bit more complex methodology, but it should run.
Get["/", true] = async (param, ct) => {
var response = Response.AsText("");
Thread.Sleep(100);
return Task.FromResult<string>(response);
};
Upvotes: 1