Speed of direct calls vs interfaces vs delegates vs virtuals

来源:互联网 发布:古代汉语词典软件下载 编辑:程序博客网 时间:2024/05/25 12:21

Speed of direct calls vs interfaces vs delegates vs virtuals

Consider the following code:

interface IProcessor
{
    void Process();
}
class Processor: IProcessor
{
    public void Process()
    {
    }
}

If I write something like:

Processor p = new Processor();
p.Process();

The compiler will emit code that tightly binds to Processor.Process(). In other words, the only function that could be called is that function.

That means that the JIT can easily inline the function call, eliminating the function call overhead totally. A discussion of when the JIT will and won't inline is beyond the scope of this post, but suffice it to say that functions below a given size will be inlined, subject to some constraints.

A brief aside: Even though C# is doing a direct call, you'll find that it's using the callvirt (ie virtual call) to do it. It does this because callvirt has a built-in null check, which means you get an exception on the invocation, rather than on the dereference inside the function.

Anyway, the direct call can easily be inlined, which is very good from a speed perspective.

But what if I have code like this:

class D
{
    public void Dispatch(IProcessor processor)
    {
        processor.Process();
    }
}

Processor p = new Processor();
D d = new D();
d.Dispatch(p);

In the calling code, we know that the function could only be Processor.Process(), but in the Dispatch() function, all the compiler knows is that it has an IProcessor reference, which could be pointing to any instance of an type that implementes IProcessor.

There is therefore no way for the JIT to inline this call - the fact that there is a level of indirection in interfaces prevents it. That's the source of the slowdown.

Virtual functions present a similar case. Like interfaces, there's a level of indirection, and the compiler can't know what type it will really get (ok, perhaps it can, but I'll cover that later.

Delegates also have a level of indirection. In the first release of .NET, our implementation of delegates wasn't as optimal as it was, and had additional overhead above the non-inlineable overhead. In Whidbey, that overhead is gone, and my tests (don't trust my tests) show that it's about as fast as interfaces, which is pretty much what one would expect.

原创粉丝点击