Поржал над комментариямя (без обид), хотя в принципе первый прав, в общем - как мы помним, у современных процессоров несколько ядер, плюс каждое ядро может выполнять несколько задач сразу и вот многопоточность - это когда несколько частей кода выполняются независимо, например два у вас работает программа, можно нажимать кнопки, она будет реагировать, но в отдельном потоке у неё будет идти цикл, который будет что-то считать.
Асинхронность тоже позволяет выполнять два цикла, но суть её в том, что куски циклов выполняются по очереди, в одном потоке - первый цикл на половину, потом второй на половину, опять первый - с середины до конца, опять второй, тоже с середины до конца, и так по порядку.
Но если использовать sleep() в Асинхронность, прервется выполнение всей программы, а в многопоточность прервется только тот поток где вызван sleep()
В свое время минусом многопоточность является процесс гонки, это когда например мы запускаем 2 части кода в разных потоках, но части из 1 потока нужен результат из 2 потока, а тот в свою очередь ещё не получен, и появляется ошибка. Это надо уже решать по своему
Вообще-то что использовать, зависит от задачи, но асинхронность все таки проще несмотря на некоторые минусы, и занимает меньше ресурсов компьютера, плюс некоторые известные библиотеки, например aiogram, используют именно асинхронность, так что стоит с ней разбираться (хотя и многопоточность тоже полезна)