В чем разница multithreading, multiprocessing и асинхронности?
Multiprocessing и multithreading относятся к стратегии управления разделяемыми ресурсами и оптимизации простоев между задачами, а Asynchronous invocation к паттернам проектирования.

Многопроцессный подход к решению позволяет скинуть обработку доступа к разделяемым ресурсам на ОС, а многопоточный позволяет самому разработчику более гибко управлять этим разделением. 

Всегда хочется писать однопоточный код, который компонуется в разные исполняемые файлы, которые можно запустить как отдельные процессы. Но проблема кроется на системном уровне - с точки зрения скорости исполнения работы процессором, задержки и ожидания передачи пакетов по сети или нахождения и чтения файла просто громадные. За то время, как решение одной задачи ждёт ответа базы данных, нерационально тратить время процессора на холостую работу активного ожидания, когда все что делает процесс, это по десять раз в мс спрашивает у ОС, пришел ли ответ, пришел ли ответ, пришел ли ответ... Пройдет много времени пока ОС поймет, что процесс ничего полезного не делает, и пока переключит контекст, выгрузит один процесс, загрузит другой, может прийти ответ для процесса, который его ждал. Но теперь придется ждать, пока ОС не загрузит его. 
Другая проблема процессного подхода - захват ресурса. Применяя многопоточность можно экономить на том, что обращаться к системным ресурсам будет  процесс, и потоки могут просто владеть ресурсом сообща, и как будет разделяться это владение решает сам разработчик. Более того, задача чтения из общей памяти более проста, если это происходит в рамках одного процесса, а межпроцессные взаимодействия всегда более тяжеловесные.

Асинхронный вызов имеет отношение к высокоуровневым языкам.  При синхронном вызове метода с точки зрения вызывающего кода происходит ожидание результата метода. При асинхронном вызове вместо ожидания происходит почти сразу переход на исполнение следующих инструкций, после вызова асинхронного метода.  
В рамках асинхронного вызова также могут быть объявлены фьючерсы и промисы, которые по факту разделяют по времени выделение памяти, инициализацию и присвоение возвращаемого асинхронным методом значения.

То, как по факту будет реализован асинхронный вызов - представляет ли он ожидание исполнения транзакции, или получения сообщения от брокера, ожидание получения результата от другого процесса или задачи, которая решается в том же процессе, но в другом потоке- это уже зависит от разработчика р выбранных проектных решений.
Почитал ответы коллег, и решил вставить свои 5 копеек:
- multiprocessing. каждая задача - это полноценный процесс ОС. процессы могут быть одинаковые, или абсолютно разные. для взаимодействия между процессами используются сокеты (про udp тактично промолчим). сокеты бывают 2 видов, сетевые и unix (юникс сокеты, естественно, присутствуют на юникс системах, под windows возможно присутствует аналогичный механизм IPC, но я не в теме, поэтому не стану сбивать вас с толку). принципиальное отличие для сокетов - это то, что через юникс сокеты взаимодействие возможно только в пределах одной машины, для сетевых сокетов такого ограничения нет.
- multithreading. главное отличие от процессов - нельзя создать самостоятельный поток, всегда сначала стартует процесс, который это делает. с точки зрения планировщика ОС отличие потоков от процессов весьма небольшое - процессы стартуют каждый в своем адресном пространстве, со своим стеком и дескрипторами. все потоки, делят адресное пространство с родителем и другими потоками. из плюсов - взаимодействие между потоками максимально быстрое, его возможности ограничены только фантазией автора программы. из минусов - взаимодействие между потоками возможно только в рамках одной программы, взаимодействие со внешним миром не отличается от случая множества процессов, из за того, что все данные доступны всем потокам сразу, приходится использовать специальные техники программирования с участием блокировок.
- асинхрон. асинхронное програмирование - это есть ни что иное, как кооперативная многозадачность. всегда есть диспетчер, который умеет переключать асинхронные задачи. в некоторых новомодных языках, вроде go, компилятор неявно вставляет вызовы диспетчера, чтобы горутины могли исполнятся паралельно. в языках, где поддержка асинхронности появилась позже, чем сам язык приходится в явном виде указывать вызываем мы синхронный или асинхронный код. при вызове асинхронного кода происходит вызов планировщика, который добавляет запрошенную функцию в очередь и производит переключение на другую задачу. иногда приходится в явном виде обращаться к диспетчеру, если, например, наша асинхронная задача будет исполняться заведомо долго.