Saya membuka file yang memiliki 100.000 URL. Saya perlu mengirim permintaan HTTP ke setiap URL dan mencetak kode status. Saya menggunakan Python 2.6, dan sejauh ini melihat banyak cara membingungkan Python mengimplementasikan threading / concurrency. Saya bahkan telah melihat pustaka persetujuan python , tetapi tidak tahu bagaimana menulis program ini dengan benar. Adakah yang mengalami masalah serupa? Saya kira secara umum saya perlu tahu bagaimana melakukan ribuan tugas dengan Python secepat mungkin - saya kira itu berarti 'bersamaan'.
python
http
concurrency
IgorGanapolsky
sumber
sumber
requests.get
danrequests.head
(mis. Permintaan halaman vs permintaan kepala) untuk mengembalikan kode status yang berbeda, jadi ini bukan saran terbaikJawaban:
Solusi twistedless:
Yang ini sedikit lebih cepat daripada solusi memutar dan menggunakan lebih sedikit CPU.
sumber
concurrent*2
?conn.close()
. Membuka terlalu banyak koneksi http dapat menghentikan skrip Anda di beberapa titik dan memakan memori.Queue
modul telah diubah namanya menjadiqueue
Python 3. Ini adalah kode Python 2.Solusi menggunakan tornado pustaka jaringan tidak sinkron
sumber
Hal-hal telah berubah sedikit sejak 2010 ketika ini diposting dan saya belum mencoba semua jawaban lain tetapi saya telah mencoba beberapa, dan saya menemukan ini berfungsi terbaik untuk saya menggunakan python3.6.
Saya dapat mengambil sekitar ~ 150 domain unik per detik yang berjalan di AWS.
sumber
time1 = time.time()
di atas for loop dantime2 = time.time()
setelah for for loop.Utas sama sekali bukan jawaban di sini. Mereka akan memberikan bottlenecks proses dan kernel, serta batas throughput yang tidak dapat diterima jika tujuan keseluruhan adalah "cara tercepat".
Sedikit
twisted
danHTTP
klien asinkronnya akan memberi Anda hasil yang jauh lebih baik.sumber
Saya tahu ini adalah pertanyaan lama, tetapi dengan Python 3.7 Anda bisa melakukan ini menggunakan
asyncio
danaiohttp
.Anda dapat membaca lebih lanjut tentang hal ini dan melihat contohnya di sini .
sumber
urls= [fetch(construct_fetch_url(u),idx) for idx, u in enumerate(some_URI_list)]
results = await asyncio.gather(*urls)
Gunakan grequests , ini kombinasi dari permintaan + modul Gevent.
GRequests memungkinkan Anda menggunakan Permintaan dengan Gevent untuk membuat Permintaan HTTP asinkron dengan mudah.
Penggunaannya sederhana:
Buat satu set Permintaan yang belum terkirim:
Kirim semuanya sekaligus:
sumber
Pendekatan yang baik untuk menyelesaikan masalah ini adalah dengan terlebih dahulu menulis kode yang diperlukan untuk mendapatkan satu hasil, kemudian memasukkan kode threading untuk memparalelkan aplikasi.
Dalam dunia yang sempurna ini berarti secara simultan memulai 100.000 utas yang menampilkan hasilnya ke kamus atau daftar untuk diproses nanti, tetapi dalam praktiknya Anda terbatas pada berapa banyak permintaan HTTP paralel yang dapat Anda terbitkan dengan cara ini. Secara lokal, Anda memiliki batasan dalam berapa banyak soket yang dapat Anda buka secara bersamaan, berapa banyak utas eksekusi yang diizinkan oleh penerjemah Python Anda. Secara jarak jauh, Anda mungkin terbatas dalam jumlah koneksi simultan jika semua permintaan bertentangan dengan satu server, atau banyak. Batasan-batasan ini mungkin mengharuskan Anda menulis skrip sedemikian rupa sehingga hanya menyurvei sebagian kecil dari URL pada suatu waktu (100, seperti poster lain yang disebutkan, mungkin merupakan ukuran kumpulan thread yang layak, meskipun Anda mungkin menemukan bahwa Anda dapat berhasil menyebarkan lebih banyak).
Anda dapat mengikuti pola desain ini untuk menyelesaikan masalah di atas:
list
ataudict
dalam CPython, Anda dapat dengan aman menambahkan atau memasukkan item unik dari utas Anda tanpa kunci , tetapi jika Anda menulis ke file atau memerlukan interaksi data cross-thread yang lebih kompleks, Anda harus menggunakan saling pengecualian mengunci untuk melindungi negara ini dari korupsi .Saya sarankan Anda menggunakan modul threading . Anda dapat menggunakannya untuk meluncurkan dan melacak utas yang sedang berjalan. Dukungan threading Python kosong, tetapi deskripsi masalah Anda menunjukkan bahwa itu sepenuhnya cukup untuk kebutuhan Anda.
Akhirnya, jika Anda ingin melihat aplikasi langsung yang cukup dari aplikasi jaringan paralel ditulis dengan Python, memeriksa ssh.py . Ini adalah perpustakaan kecil yang menggunakan threading Python untuk memparalelkan banyak koneksi SSH. Desainnya cukup dekat dengan kebutuhan Anda sehingga Anda mungkin menganggapnya sebagai sumber yang bagus.
sumber
Jika Anda mencari untuk mendapatkan kinerja terbaik, Anda mungkin ingin mempertimbangkan untuk menggunakan Asynchronous I / O daripada utas. Overhead yang terkait dengan ribuan utas OS adalah non-sepele dan konteks beralih dalam juru bahasa Python menambahkan lebih banyak di atasnya. Threading pasti akan menyelesaikan pekerjaan tetapi saya menduga bahwa rute yang tidak sinkron akan memberikan kinerja keseluruhan yang lebih baik.
Secara khusus, saya sarankan klien web async di perpustakaan Twisted ( http://www.twistedmatrix.com ). Ini memiliki kurva belajar yang jelas curam tetapi cukup mudah digunakan setelah Anda mendapatkan pegangan yang baik pada gaya pemrograman asinkron Twisted.
API klien web asinkron Twisted's HowTo tersedia di:
http://twistedmatrix.com/documents/current/web/howto/client.html
sumber
Sebuah solusi:
Waktu tes:
Pingtime:
sumber
Menggunakan thread pool adalah pilihan yang baik, dan akan membuat ini cukup mudah. Sayangnya, python tidak memiliki pustaka standar yang membuat thread thread sangat mudah. Tapi di sini ada perpustakaan yang layak yang harus Anda mulai: http://www.chrisarndt.de/projects/threadpool/
Contoh kode dari situs mereka:
Semoga ini membantu.
sumber
q_size
> 0 ukuran antrian permintaan pekerjaan terbatas dan utas kolam memblokir ketika antrian penuh dan mencoba memasukkan lebih banyak permintaan kerja di dalamnya (lihatputRequest
metode), kecuali jika Anda juga menggunakantimeout
nilai positif untukputRequest
."Buat
epoll
objek,terbuka banyak soket klien TCP,
menyesuaikan buffer kirim mereka untuk menjadi sedikit lebih dari header permintaan,
mengirim header permintaan - itu harus segera, hanya menempatkan ke dalam buffer, daftar soket di
epoll
objek,lakukan
.poll
padaepoll
obect,baca pertama 3 byte dari setiap soket dari
.poll
,tulis mereka
sys.stdout
diikuti\n
(jangan siram), tutup soket klien.Batasi jumlah soket yang dibuka secara bersamaan - menangani kesalahan saat soket dibuat. Buat soket baru hanya jika yang lain ditutup.
Sesuaikan batas OS.
Coba gunakan beberapa proses (tidak banyak): ini mungkin membantu menggunakan CPU sedikit lebih efektif.
sumber
Untuk kasus Anda, threading mungkin akan melakukan trik karena Anda mungkin akan menghabiskan sebagian besar waktu menunggu jawaban. Ada modul bermanfaat seperti Antrian di perpustakaan standar yang mungkin membantu.
Saya melakukan hal yang sama dengan mengunduh file secara paralel sebelumnya dan itu cukup baik untuk saya, tetapi itu tidak pada skala yang Anda bicarakan.
Jika tugas Anda lebih terikat CPU, Anda mungkin ingin melihat modul multiprosesing , yang akan memungkinkan Anda untuk memanfaatkan lebih banyak CPU / core / utas (lebih banyak proses yang tidak akan memblokir satu sama lain karena penguncian adalah per proses)
sumber
Pertimbangkan untuk menggunakan Windmill , walaupun Windmill mungkin tidak dapat melakukan banyak thread.
Anda bisa melakukannya dengan skrip Python digulung tangan pada 5 mesin, masing-masing menghubungkan keluar menggunakan port 40000-60000, membuka 100.000 koneksi port.
Juga, mungkin membantu untuk melakukan uji sampel dengan aplikasi QA yang diulir dengan baik seperti OpenSTA untuk mendapatkan gambaran tentang seberapa banyak yang dapat ditangani oleh setiap server.
Selain itu, coba lihat menggunakan Perl sederhana dengan kelas LWP :: ConnCache. Anda mungkin akan mendapatkan lebih banyak kinerja (lebih banyak koneksi) dengan cara itu.
sumber
Klien web bengkok async ini berjalan cukup cepat.
sumber
Saya menemukan bahwa menggunakan
tornado
paket menjadi cara tercepat dan termudah untuk mencapai ini:sumber
Cara termudah adalah dengan menggunakan pustaka threading bawaan Python.
Mereka bukan "nyata" / utas kernel.Mereka memiliki masalah (seperti serialisasi), tetapi cukup baik. Anda ingin antrian & kumpulan utas. Satu opsi ada di sini , tetapi sepele untuk menulis sendiri. Anda tidak dapat memparalelkan semua 100.000 panggilan, tetapi Anda dapat mematikan 100 (atau lebih) dari mereka secara bersamaan.sumber