На самом деле в большинстве операционных систем нет поддержки асинхронных операций с файлами. Поэтому и в asyncio её нет. Все существующие сторонние реализации, такие как этот самый aiofiles (как и реализации в других языках, например в node.js) внутри используют пул тредов. Если не хочешь использовать стороннюю реализацию, я не вижу ничего зазорного использовать отдельный тред. Но нужно хорошо понимать, что ты делаешь.
Как собираетесь записывать файл из нескольких потоков одновременно? Синхронизировать очерёдность? Не стоит 1000 раз переоткрывать файлы, большые расходы. Создаёте отдельный тред для записи файлов, ему скармливаете всё что надо записать.
Ну тогда создаёте отдельный поток для записи файлов, он динамически создаёт тредов в пределах ожидаемого количества соединений, по 1 на каждое соединение. В него скачивающий процесс из своих тредов переправляет свои данные. Но это может быть оверинжиниринг, зависит от задач. Обычно достаточно отдельный пул тредов для скачивания и отдельный 1 тред с очередью на запись на диск, в одном процессе. Только это возможно будет медленней чем много потоков из-за GIL, надо тестировать нагрузки.
Если качаешь файлы параллельно, то и писать их будешь параллельно (например, повесив коллбеки на скачивание или каким-то другим образом скомпозировав эти две процедуры).
А если качаешь один файл кусками (типа как торренты, но я думаю, что тебе это не нужно, иначе бы ответ знал и так), можно синхронизироваться любым удобным способом и скакать по файлу, записывая куски. Можно что-то типа mmap (погугли python memory mapped file), но вообще - это не то, что тебе нужно, просто для кругозора.
Покажи код лучше, как качаешь, а то кажется, что сам не знаешь, что хочешь.