Blocks are downloaded in series from a given peer, but a node can download blocks from multiple peers at the same time, effectively downloading blocks in parallel. This parallel downloading is not about downloading different parts of the same block from different peers, but rather downloading different blocks from different peers.
This design allows a node to download the blockchain more quickly, as it is not limited by the upload speed of a single peer. It also adds a layer of redundancy.
Despite the parallel downloading of blocks, they must be processed serially. This is essential for the node to maintain accurate information about the existing unspent transaction outputs (UTXOs) and to verify the validity of transactions.
The actual implementation of this process in Bitcoin Core is quite complex and involves various aspects like handling timeouts, validating blocks, and so on. You can review the actual code in the Bitcoin Core GitHub repository to get a deeper understanding.
You may also check the P2P Network part of Bitcoin Developer site – see the explanation for Block, GetBlocks, GetData, GetHeaders messages, that are involved when blocks are sent between nodes.