Katakanlah kita memiliki fungsi dummy:
async def foo(arg):
result = await some_remote_call(arg)
return result.upper()
Apa perbedaan antara:
import asyncio
coros = []
for i in range(5):
coros.append(foo(i))
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(coros))
Dan:
import asyncio
futures = []
for i in range(5):
futures.append(asyncio.ensure_future(foo(i)))
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(futures))
Catatan : Contoh mengembalikan hasil, tetapi ini bukan fokus pertanyaan. Ketika hal-hal nilai kembali, menggunakan gather()
bukan wait()
.
Terlepas dari nilai pengembaliannya, saya mencari kejelasan tentang ensure_future()
. wait(coros)
dan wait(futures)
keduanya menjalankan coroutine, jadi kapan dan mengapa coroutine harus digabungkan ensure_future
?
Pada dasarnya, apa Cara yang Benar (tm) untuk menjalankan banyak operasi non-pemblokiran menggunakan Python 3.5 async
?
Untuk kredit ekstra, bagaimana jika saya ingin melakukan batch panggilan? Misalnya, saya perlu menelepon some_remote_call(...)
1000 kali, tetapi saya tidak ingin menghancurkan server web / database / dll dengan 1000 koneksi simultan. Ini dapat dilakukan dengan utas atau kumpulan proses, tetapi adakah cara untuk melakukannya asyncio
?
Pembaruan 2020 (Python 3.7+) : Jangan gunakan cuplikan ini. Sebagai gantinya gunakan:
import asyncio
async def do_something_async():
tasks = []
for i in range(5):
tasks.append(asyncio.create_task(foo(i)))
await asyncio.gather(*tasks)
def do_something():
asyncio.run(do_something_async)
Pertimbangkan juga untuk menggunakan Trio , alternatif pihak ketiga yang tangguh untuk asyncio.
sumber
ensure_future()
? Dan jika saya membutuhkan hasilnya, tidak bisakah saya menggunakan sajarun_until_complete(gather(coros))
?ensure_future
menjadwalkan coroutine untuk dieksekusi dalam event loop. Jadi saya akan mengatakan ya, itu wajib. Tetapi tentu saja Anda dapat menjadwalkan coroutine menggunakan fungsi / metode lain juga. Ya, Anda dapat menggunakangather()
- tetapi kumpul akan menunggu hingga semua tanggapan terkumpul.gather
danwait
benar - benar menggabungkan coroutine yang diberikan sebagai tugas yang menggunakanensure_future
(lihat sumber di sini dan di sini ). Jadi tidak ada gunanya menggunakanensure_future
sebelumnya, dan itu tidak ada hubungannya dengan mendapatkan hasil atau tidak.ensure_future
memilikiloop
argumen, jadi tidak ada alasan untuk menggunakanloop.create_task
lebihensure_future
. Danrun_in_executor
tidak akan berfungsi dengan coroutine, semaphore harus digunakan sebagai gantinya.create_task
lebihensure_future
, lihat docs . Kutipancreate_task() (added in Python 3.7) is the preferable way for spawning new tasks.
Jawaban sederhana
async def
) TIDAK menjalankannya. Ini mengembalikan objek coroutine, seperti fungsi generator mengembalikan objek generator.await
mengambil nilai dari coroutine, yaitu "memanggil" coroutineeusure_future/create_task
jadwalkan coroutine untuk dijalankan pada loop acara pada iterasi berikutnya (meskipun tidak menunggu hingga selesai, seperti untaian daemon).Beberapa contoh kode
Pertama mari kita jelaskan beberapa istilah:
async def
s;Kasus 1,
await
di coroutineKami membuat dua coroutine,
await
satu, dan digunakancreate_task
untuk menjalankan yang lain.Anda akan mendapatkan hasil:
Menjelaskan:
task1 dijalankan secara langsung, dan task2 dijalankan dalam iterasi berikut.
Kasus 2, menghasilkan kontrol ke loop peristiwa
Jika kita mengganti fungsi utama, kita bisa melihat hasil yang berbeda:
Anda akan mendapatkan hasil:
Menjelaskan:
Saat memanggil
asyncio.sleep(1)
, kontrol dikembalikan ke loop peristiwa, dan loop memeriksa tugas yang akan dijalankan, lalu menjalankan tugas yang dibuat olehcreate_task
.Perhatikan bahwa, pertama-tama kami memanggil fungsi coroutine, tetapi tidak
await
, jadi kami hanya membuat satu coroutine, dan tidak membuatnya berjalan. Kemudian, kita memanggil fungsi coroutine lagi, dan membungkusnya dengancreate_task
panggilan, creat_task akan menjadwalkan coroutine untuk dijalankan pada iterasi berikutnya. Jadi hasilnyacreate task
dieksekusi sebelumnyaawait
.Sebenarnya, intinya di sini adalah untuk mengembalikan kontrol ke loop, Anda bisa menggunakan
asyncio.sleep(0)
untuk melihat hasil yang sama.Dibawah tenda
loop.create_task
sebenarnya meneleponasyncio.tasks.Task()
, yang akan meneleponloop.call_soon
. Danloop.call_soon
akan memasukkan tugasloop._ready
. Selama setiap iterasi loop, ia memeriksa setiap callback di loop._ready dan menjalankannya.asyncio.wait
,asyncio.ensure_future
danasyncio.gather
meneleponloop.create_task
secara langsung atau tidak langsung.Perhatikan juga di dokumen :
sumber
await task2
panggilan tersebut dapat diperjelas. Dalam kedua contoh tersebut, panggilan loop.create_task () adalah yang menjadwalkan tugas2 pada loop peristiwa. Jadi di kedua mantan Anda dapat menghapusawait task2
dan tetap saja task2 pada akhirnya akan berjalan. Di ex2 perilakunya akan sama, karenaawait task2
saya yakin hanya menjadwalkan tugas yang sudah selesai (yang tidak akan berjalan untuk kedua kalinya), sedangkan di ex1 perilakunya akan sedikit berbeda karena tugas2 tidak akan dijalankan sampai main selesai. Untuk melihat perbedaannya, tambahkanprint("end of main")
di akhir main ex1Sebuah komentar oleh Vincent tertaut ke https://github.com/python/asyncio/blob/master/asyncio/tasks.py#L346 , yang menunjukkan bahwa
wait()
membungkus coroutine diensure_future()
untuk Anda!Dengan kata lain, kita memang membutuhkan masa depan, dan coroutine akan diam-diam diubah menjadi masa depan.
Saya akan memperbarui jawaban ini ketika saya menemukan penjelasan pasti tentang cara menumpuk coroutines / futures.
sumber
c
,await c
setara denganawait create_task(c)
?Dari BDFL [2013]
Tugas
Dengan pemikiran ini,
ensure_future
masuk akal sebagai nama untuk membuat Tugas karena hasil Future akan dihitung apakah Anda menunggunya atau tidak (selama Anda menunggu sesuatu). Ini memungkinkan event loop menyelesaikan Tugas Anda saat Anda menunggu hal lain. Perhatikan bahwa di Python 3.7create_task
adalah cara yang lebih disukai untuk memastikan masa depan .Catatan: Saya mengubah "hasil dari" dalam slide Guido menjadi "menunggu" di sini untuk modernitas.
sumber