Чем отличается генератор от корутины?
Ответ Дмитрий Шицков был бы хорош лет 5 назад, но сейчас нуждается в уточнении.  PEP 492, все дела.import asyncio, warnings, itertools

def a():
    for ch in 'foo':
        print(ch, 'from a')
        yield

@asyncio.coroutine
def b():
    for ch in 'foo':
        print(ch, 'from b')
        yield

async def c():
    for ch in 'foo':
        print(ch, 'from c')
        await asyncio.sleep(0)

print('как ни странно, здесь все три прокатывают\n')
loop = asyncio.get_event_loop()
tasks = [loop.create_task(f()) for f in (a, b, c)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

print('\nмежду тем, есть нюансы\n')
with warnings.catch_warnings():
    warnings.simplefilter('ignore')
    dirs = [[*dir(f), *dir(f())] for f in (a, b, c)]
for s in sorted(set(itertools.chain(*dirs))):
    if not all(s in d for d in dirs):
        print(f'{s:14}', *['-+'[s in d] for d in dirs])
Видно, что a и b отличаются лишь тем, что b зарегистрирована как корутина, а вот c вовсе другая.
Займись этим вопросом, чо нароешь - отпишись.
Тем что корутина выполняется в отдельном асинхронном потоке?