Я прийшов сюди досить комфортно з двома поняттями, але з чимось незрозумілим мені про них.
Прочитавши деякі відповіді, я думаю, що у мене є правильна і корисна метафора, щоб описати різницю.
Якщо ви вважаєте, що ваші окремі рядки коду є окремими, але впорядкованими гральними картами (зупиніть мене, якщо я пояснюю, як працюють перфокарти старої школи), то для кожної окремо написаної процедури у вас буде унікальний стоп карт (не Скопіюйте та вставіть!), і різниця між тим, що зазвичай відбувається при нормальному та асинхронному виконанні коду, залежить від того, дбаєте ви чи ні.
Коли ви запускаєте код, ви передаєте ОС набір одиночних операцій (щоб ваш компілятор або інтерпретатор перебив ваш код "вищого рівня"), який буде переданий процесору. З одним процесором може бути виконаний лише один рядок коду за один раз. Отже, для того, щоб створити ілюзію запуску декількох процесів одночасно, ОС використовує техніку, в якій вона надсилає процесору лише кілька рядків із заданого процесу одночасно, перемикаючись між усіма процесами відповідно до того, як він бачить підходить. Результат - це кілька процесів, що показують прогрес кінцевому користувачеві в той час, що, здається, одночасно.
Для нашої метафори взаємозв'язок полягає в тому, що ОС завжди переміщує картки перед тим, як надсилати їх процесору. Якщо ваш стек карт не залежить від іншого стека, ви не помічаєте, що ваш стек перестав вибиратись, поки інший стек став активним. Тож якщо вам все одно, це не має значення.
Однак якщо вам все-таки важливо (наприклад, є кілька процесів - чи стоси карток - які залежать один від одного), тоді перемішування ОС перекриє ваші результати.
Написання асинхронного коду вимагає вирішення залежностей між порядком виконання незалежно від того, чим закінчується це замовлення. Ось чому використовуються такі конструкції, як "зворотні дзвінки". Вони говорять процесору, "наступне, що потрібно зробити, це сказати іншому стеку, що ми зробили". Використовуючи такі інструменти, ви можете бути впевнені, що інший стек отримує повідомлення, перш ніж він дозволить ОС виконувати більше своїх інструкцій. ("Якщо call_back == false: send (no_operation)" - не впевнений, чи це насправді так реалізовано, але логічно, я вважаю, що це відповідає.)
Для паралельних процесів різниця полягає в тому, що у вас є два стеки, які не дбають один про одного, і два робітники для їх обробки. Зрештою, вам може знадобитися об'єднати результати з двох стеків, що потім буде справою синхронності, але для виконання вас знову не хвилює.
Не впевнений, чи це допомагає, але я завжди вважаю корисними пояснення. Також зауважте, що асинхронне виконання не обмежується окремим комп'ютером та його процесорами. Взагалі кажучи, це стосується часу, або (ще загальніше кажучи) порядку подій. Отже, якщо ви надсилаєте залежний стек A до вузла мережі X та його зв'язаного стека B до Y, правильний асинхронний код повинен мати можливість враховувати ситуацію, як ніби він працює локально на вашому ноутбуці.