Я просматривал библиотеку aiodocker .
И в документации указано, что они смотрят тег python-asyncio
. Поэтому я хотел спросить о том, как асинхронизировать мой код докера, так как я не мог понять это из документации и исходного кода. Вот код, который мне нужен для асинхронизации (detach=True
ниже не будет работать, потому что иногда контейнер завершает работу с ненулевым кодом состояния. Их асинхронность поможет мне лучше справиться с этим.):
import docker
def synchronous_request(url):
client = docker.from_env()
local_dir = '/home/ubuntu/git/docker-scraper/data'
volumes = {local_dir: {'bind': '/download/', 'mode': 'rw'}}
environment = {'URL': url}
client.containers.run('wgettor:latest', auto_remove=True, volumes=volumes, environment=environment)
Моя попытка с aiodocker
:
import aiodocker
async def make_historical_request(url):
docker = await aiodocker.Docker()
client = await aiodocker.DockerContainers(docker)
local_dir = '/home/ubuntu/git/docker-scraper/data'
volumes = {local_dir: {'bind': '/download/', 'mode': 'rw'}}
environment = {'URL': url}
await client.run(config={"auto_remove": "True",
"volumes": volumes,
"environment": environment}, name="wgettor:latest")
Буду признателен, если вы покажете мне, как это сделать правильно.
Попытка достичь чего-то подобного (ниже не будет работать одновременно):
import docker
import asyncio
from collections import namedtuple
URL = namedtuple('URL', 'val')
URLs = (
URL('https://www.google.com'),
URL('https://www.yahoo.com')
)
client = docker.from_env()
local_dir = '/home/ubuntu/git/docker-scraper/data-test'
volumes = {local_dir: {'bind': '/download/', 'mode': 'rw'}}
async def run_container(client, volumes, environment, *, pid):
print("Starting the container on pid: {}".format(pid))
return client.containers.run('wgettor:latest', auto_remove=True, detach=True,
volumes=volumes, environment=environment)
async def make_historical_request(url, *, pid):
print("Starting the retrieval of: {}, on pid: {}".format(url, pid))
environment = {'URL': url}
return await run_container(client, volumes, environment, pid=pid)
async def main():
tasks = [asyncio.ensure_future(make_historical_request(url.val, pid=ix)) for ix, url in enumerate(URLs)]
await asyncio.wait(tasks)
if __name__ == '__main__':
asyncio.run(main())
С помощью Фрейнда Аллайнда я считаю, что это должно быть примерно так:
async def run_container(docker, url):
config = {
'Env': ["URL="+url],
'HostConfig': {
'Binds': local_dir + ":" + "/download/"
}
}
try:
await asyncio.sleep(random.random() * 0.001)
container = await docker.containers.create_or_replace(
config=config,
name="wgettor:latest",
)
await container.start()
await container.kill()
return url
except DockerError as err:
print(f'Error starting wgettor:latest, container: {err}')
async def main():
start = time.time()
docker = Docker()
futures = [run_container(docker, url) for url in URLs]
# futures = [fetch_async(i) for i in range(1, MAX_CLIENTS + 1)]
for i, future in enumerate(asyncio.as_completed(futures)):
result = await future
print('{} {}'.format(">>" * (i + 1), result))
print("Process took: {:.2f} seconds".format(time.time() - start))