asyncio.open_connection порождает вызов
socket.getaddrinfo в
loop._default_executor, который в 3.7 по-умолчанию является
ThreadPoolExecutor. Максимальное число воркеров в пуле по-умолчанию определяется
max_workers = (os.cpu_count() or 1) * 5 (
ссылка).
В 3.8 это изменят на
min(32, (os.cpu_count() or 1) + 4),
коммит.
Можете изменить число создаваемых потоков, передав свой экземпляр ThreadPoolExecutor:
import concurrent.futures
...
loop = asyncio.get_event_loop()
loop.set_default_executor(concurrent.futures.ThreadPoolExecutor(max_workers=4))
...