You probably shouldn't be learning assembler. First, compilers are really quite good. Yes, it's possible to beat them (I do) but generally not by much. And not by much ain't gonna put bacon on the table. You can probably get what you need from gcc inline asm() calls. Take a look at the linux sources and figure out why and when assembly is used there:
http://stackoverflow.com/questions/22122887/linux-kernel-ass...
Secondly, writing in assembler is not low level. You just think it is. You should really be understanding caches and you can improve your cache performance in C.
Anyways, unless you deeply know what's going on inside of the microarchitecture of a modern superscalar, out of order, speculative, renaming, μop-cached, hyper-threaded, multicore beast then you shouldn't be fooling yourself by writing in assembler.
http://blog.erratasec.com/2015/03/x86-is-high-level-language...
Unless you've really read Intel's Intel 64 and IA-32 Architectures Optimization Reference Manual (and ARM's Cortex®-A72 Software Optimization Guide) and meditated on the suras of Agner Fog's Microarchitecture you won't even know what's going on with something as simple as mov RAX, RBX.
Look, most compiler writers don't even know this stuff (Intel C Compiler yes, llvm occasionally) and frankly, it isn't very useful because Intel spends a billion dollars a year to make your bad x86 code run reasonably fast. Consider a switch statement which compiles into an indirect branch, jmp reg. That branch has to be predicted by the BTB before the jmp reg instruction is even fetched and that's really hard to do. Every year they get better and better to the point that you're not even aware of it. But if you want to the help the CPU out, you could put a UD2 right after the jmp reg. This is insanely hard to understand and will help very little.
Don't go there.