Jay_H wrote:Now then, taking a step back. Narf, I don't yet have a clear understanding of the difference between calling from memory and caching, and the meaning of the word "struct." I'm halfway through and I feel like I'm missing some vital points because of it. Would you be able to explain them further?
Sure.
Ok, so the different storage mediums in your computer can return data at different speeds. SSDs (solid-state drives) are faster than HDDs (hard disk drives). RAM is faster than SSDs. Your CPU has its own, on-chip RAM that's even faster, since it's in the same chip. Modern CPUs will try to figure out what data they need, and fetch it to their on-chip cache. If the data isn't in the CPU's cache, you have a cache miss, and from there, it can take thousands to hundreds of thousands of CPU cycles before the data arrives. Lastly, and most immediate, CPUs have registers, which contain small amounts of data that the CPU can operate on without delay.
But I should probably explain what a CPU cycle is, before I go further. Ok, so you know how your computer has some speed rating in "GHz", or "Gigahertz"? That's the number of times your CPU can cycle per second. "Hertz" is a quick way of saying "per second"; if you type at 3 keyboard presses per second, you type at 3 keyboard press hertz. "Giga" is a metric prefix meaning "billion".
Yes, your computer is running up to 4.x billion cycles per second.
Ok, so what do cycles mean? Everything your computer does takes a certain number of cycles. For example, Intel's Skylake CPUs take 4 cycles to do one floating-point operation. So if you want to add, multiply, divide (modulo and power functions are derived from the other three) floats, and you have a 4 GHz CPU, you can do 1 billion of those per second...Under optimal conditions.
However, there's some reasons why you probably won't be able to. First, there's the overhead of whatever loop you're running. Second, there's whatever else is running on your OS. Third, if the data is not in the registers, it has to be fetched from the cache. If it's not in the cache...Well, the CPU might have to call all the way out to that spinning magnetic platter of a HDD. This is called a cache miss, BTW.
Ok, so if you want some data, you could do one of these:
Code: Select all
Data CalculateData(//... Inputs)
{
/// Calculate.
}
Code: Select all
private Data cachedData;
private bool cachedDataChanged;
Data CalculateData(//... Inputs)
{
// Why (cachedDataChanged == false) and not (!cachedDataChanged)?
// The former makes it clear what you want, and is less likely to get missed
// or accidentally deleted.
if (cachedDataChanged == false)
return cachedData;
else
{
// Calculate.
cachedData = calculatedData;
return cachedData;
}
}
Now, which is faster? ...It depends. Calculating the data might be faster, because the inputs are close to the CPU, and the calculation is fast. OTOH, returning the cached data might be faster, because the CPU's already preloaded it, and it was close enough to the CPU. And maybe the calculation is slow. Either one can take more CPU cycles; as always, test.
Ok, so that's caching, and calculating data. What's a method call?
First, how are methods stored? Methods are stored in memory, and when you call a method, you literally copy that data to the CPU. While your computer receives it in the context of instructions, and not data, the exact same notes about CPU cycles applies.
But it's more than that, too.
Programs store data in one of two ways: On the stack, and on the heap. The stack is just that, a stack; add things to the top, take things off the top...Works pretty much the same (in the general sense) as C#'s Stack class.
The heap is a heap. You can put things anywhere, and you can retrieve them without worrying about the order of things...As long as you know where stuff is, you can get it out.
You may have heard about pointers. Pointers point into the heap, allowing something to be retrieved.
Methods are called using pointers. So, when you call a method, you pop a pointer from the stack, push a marker noting where the method should return to, to the stack, push all the parameters of the method onto the stack, jump to that pointer (so the CPU continues execution at that pointer) which pulls the method's instructions to the CPU... So yeah, calling into a method is slow. You might think you should make one larger method to reduce method calls, but the larger it is, the longer it takes to load the instructions to the CPU (and if it's big enough, the CPU might have to fetch instructions more than once). It's a trade-off.
So, that's a method call, and why it's slow.
Now, to explain structs. Don't worry, it won't take long. Structs are data that is stored on the stack. As a corollary, classes are stored on the heap. So, structs can be faster, because the data is right there on the stack. Conversely, classes can be faster, because you only have to pass a pointer...And a pointer is an Int32 or Int64 in fancy dress. Int32 on a 32-bit platform; Int64 on a 64-bit platform.
A reference (C# uses references) is a pointer in fancy dress.
I've left out some abstractions, and how C# defines structs and classes is specific to C#.
Oh, and I should note that both the stack and the heap are stored in RAM.
Hopefully that makes things at least a little less muddy.