Multiprogramming allows multiple programs to share processor resources while multi-threading allows a program to split itself into multiple, simultaneously executing threads. Assembly language should generally be avoided but may be useful for performance-critical code or when close interaction with hardware is needed. Compiled languages have performance advantages over interpreted languages but interpreted languages are more portable and allow for interactive development. Superscalar processing improves performance over scalar pipelines by allowing multiple instructions to execute simultaneously through parallel pipelines while superpipelining breaks instructions into smaller sub-parts to reduce idle times between instructions.