views:

323

answers:

4

Is it expensive?

I am developing an HtmlHelper that renders directly to Response.Output in order to save unnecesary string creation and I need to choose between:

<% Validator.RenderClient(Response.Output); %>

and

<% Validator.RenderClient(); %>

and get the textWriter from HttpContext.Current.Response

+2  A: 

from reflector

public static HttpContext get_Current()
{
    return (ContextBase.Current as HttpContext);
}

calls ContextBase which calls

public static object HostContext
{
    get
    {
        object hostContext = 
          Thread.CurrentThread.GetIllogicalCallContext().HostContext;
        if (hostContext == null)
        {
            hostContext = GetLogicalCallContext().HostContext;
        }
        return hostContext;
    }

...

so there is a bit of threading 'stuff' going on; the specific I don't really know.

Greg Ogle
For some reason I find it interesting that they seem to prefer what the illogical call context returns over what the logical call context would return (whatever those things are).
Michael Burr
A: 

I would assume from Oglester's answer that it is not intensive.

If it was intensive, I'm guessing they would have (most likely anyway) implemented this as a method opposed to a property

John
+2  A: 

It is not intensive at all. I don't know why I didn't try this the first time:

        System.Diagnostics.Stopwatch sp = new System.Diagnostics.Stopwatch();

        // With HttpContext.Current:
        sp.Start();
        for (int i = 0; i < 100; i++)
        {
            HttpContext.Current.Response.Output.Write(i.ToString());
        }
        sp.Stop();
        long result1 = sp.ElapsedTicks;

        // Without:
        TextWriter output2 = HttpContext.Current.Response.Output;
        sp.Reset();
        sp.Start();
        for (int i = 0; i < 100; i++)
        {
            output2.Write(i.ToString());
        }
        sp.Stop();
        long result2 = sp.ElapsedTicks;

And my computer results are around:

result1= 395 ticks result2= 332 ticks

So it is pretty fast!

Dawkins
I have issues with our way of conducting performance tests, see my answer below. Your right in your answer, but the results are not accurate (statistically viable).
John Leidegren
+2  A: 

@Dawkins

100 runs is too few, you need to run about 10000 times several times and repeat it and then take the average of that to get a reliable result. The margin of error is to big in your example, but it's the right way to go.

Here's what i did:

var results1 = new List<long>();
var results2 = new List<long>();

for (int j = 0; j < 100; j++)
{
    var sp = new System.Diagnostics.Stopwatch();

    // With HttpContext.Current: 
    sp.Start();
    for (int i = 0; i < 10000; i++)
    {
        HttpContext.Current.Response.Output.Write(i);
    }
    sp.Stop();

    results1.Add(sp.ElapsedTicks);

    // Without: 
    TextWriter output2 = HttpContext.Current.Response.Output;
    sp.Reset();

    sp.Start();
    for (int i = 0; i < 10000; i++)
    {
        output2.Write(i);
    }
    sp.Stop();

    HttpContext.Current.Response.Clear();

    results2.Add(sp.ElapsedTicks);
}

results1.Sort();
results2.Sort();

HttpContext.Current.Response.Write(string.Format("HttpContext.Current={0:0.000}ms, Local variable={1:0.000}ms, R={2:0.0%}<br/>", results1[results1.Count / 2] / (double)TimeSpan.TicksPerMillisecond, results2[results2.Count / 2] / (double)TimeSpan.TicksPerMillisecond, (double)results1[results1.Count / 2] / (double)results2[results2.Count / 2]));

Your result show that there's a 18% performance difference, which shows that it's more expensive but it off by 8%.

I re-ran the numbers several times and came up with a 10% difference with a error margin of less then 1%.

It stablaizes around:

HttpContext.Current=0,536ms, Local variable=0,486ms, R=110,2% 

Anyway, HttpContext.Current to pose a significant performance problem you'll need to call it way more than 10000 per request (the cost is largely made up by the Response.Write calls). And that's likely not going to happen.

John Leidegren