Давайте начнем с конца.
Когда ваш PHP заканчивает выполнение вашего скрипта, он выполняет очистку и убивает все еще работающие ручки curl. Важно помнить это.
Теперь каждый запрос скручивания разделен на несколько этапов, таких как инициализация соединения, подключение, запись данных, чтение данных, закрытие соединения. Средние шаги могут повторяться. И я уверен, что на самом деле за кулисами происходят более сложные вещи, но в целом это описание должно быть правильным.
curl_multi_exec дает управление каждому из дескрипторов в мульти дескрипторе и позволяет ему выполнить следующий шаг, каким бы он ни был. И тогда функция возвращает.
Это объясняет, почему вы не видите запрос без цикла. Это происходит потому, что ваш дескриптор еще не достиг шага, на котором он может выполнить фактическое соединение. Ваш PHP-скрипт завершает работу, выполняет очистку, которая, в свою очередь, убивает дескриптор, у которого вообще не было возможности что-либо сделать.
Итак, теперь ясно, что вам нужно дать ручке шанс что-то сделать. Запуск curl_multi_exec снова и снова является одним из способов достижения этого.
Это объясняет, почему вы испытываете ожидание, эти множественные дескрипторы на самом деле не асинхронны, они просто выглядят так, как они. Ваш цикл дает дескриптору возможность работать, и цикл будет продолжаться до тех пор, пока не завершится запрос (что в вашем примере занимает 10 секунд).
Краткое резюме: вам нужно найти другое решение вашей проблемы (которое заключается в продолжении выполнения другого кода, пока выполняется curl):)