পাইথনে 100,000 এইচটিটিপি অনুরোধ প্রেরণের দ্রুততম উপায় কী?


287

আমি একটি ফাইল খুলছি যা 100,000 ইউআরএল রয়েছে। আমার প্রতিটি ইউআরএলতে একটি HTTP অনুরোধ প্রেরণ এবং স্থিতি কোড মুদ্রণ করা দরকার। আমি পাইথন ২.6 ব্যবহার করছি এবং এখনও অবধি পাইথন থ্রেডিং / সমঝোতা প্রয়োগ করে এমন অনেক বিভ্রান্তিকর উপায়ে দেখেছি। এমনকি আমি অজগর সম্মিলনের গ্রন্থাগারটিও দেখেছি , তবে কীভাবে এই প্রোগ্রামটি সঠিকভাবে লিখতে হবে তা অনুমান করতে পারি না। কেউ কি একই ধরনের সমস্যা জুড়ে এসেছেন? আমি অনুমান করি যে পাইথনে যত দ্রুত সম্ভব হাজারো কাজ সম্পাদন করতে হবে তা আমার জানা দরকার - আমি মনে করি এর অর্থ 'একযোগে'।


47
নিশ্চিত হয়ে নিন যে আপনি কেবল প্রধান অনুরোধটি করেছেন (যাতে আপনি পুরো দস্তাবেজটি ডাউনলোড না করেন)। দেখুন: stackoverflow.com/questions/107405/...
Tarnay কালমান

5
দুর্দান্ত পয়েন্ট, কলমি। সমস্ত ইগর যদি অনুরোধের স্থিতি চায় তবে এই 100 কে অনুরোধগুলি অনেক বেশি, আরও দ্রুত চলে যাবে। অনেক দ্রুত।
অ্যাডাম ক্রসল্যান্ড

1
এর জন্য আপনার থ্রেডের দরকার নেই; সবচেয়ে কার্যকরী উপায়টি সম্ভবত ট্যুইস্টের মতো একটি অ্যাসিনক্রোনাস লাইব্রেরি ব্যবহার করবে।
jemfinch

3
এখানে জেনভেট, পাকানো এবং অ্যাসিনসিও ভিত্তিক কোড উদাহরণ রয়েছে (1000000 অনুরোধে পরীক্ষা করা হয়েছে)
jfs

4
@ তার্নেকেক্লমন তার পক্ষে requests.getএবং requests.head(যেমন একটি মাথা অনুরোধের তুলনায় একটি পৃষ্ঠার অনুরোধ) বিভিন্ন স্থিতি কোডগুলি ফিরিয়ে আনার পক্ষে সম্ভব , সুতরাং এটি সর্বোত্তম পরামর্শ নয়
আলেক্সজি

উত্তর:


200

পাকানো সমাধান:

from urlparse import urlparse
from threading import Thread
import httplib, sys
from Queue import Queue

concurrent = 200

def doWork():
    while True:
        url = q.get()
        status, url = getStatus(url)
        doSomethingWithResult(status, url)
        q.task_done()

def getStatus(ourl):
    try:
        url = urlparse(ourl)
        conn = httplib.HTTPConnection(url.netloc)   
        conn.request("HEAD", url.path)
        res = conn.getresponse()
        return res.status, ourl
    except:
        return "error", ourl

def doSomethingWithResult(status, url):
    print status, url

q = Queue(concurrent * 2)
for i in range(concurrent):
    t = Thread(target=doWork)
    t.daemon = True
    t.start()
try:
    for url in open('urllist.txt'):
        q.put(url.strip())
    q.join()
except KeyboardInterrupt:
    sys.exit(1)

এইটি বাঁকা সমাধানের চেয়ে সামান্য দ্রুত এবং কম সিপিইউ ব্যবহার করে।


10
@ কলমী, আপনি সারি কেন সেট করেছেন concurrent*2?
মার্সেল উইলসন

8
সংযোগটি বন্ধ করতে ভুলবেন না conn.close()। অনেকগুলি HTTP সংযোগ খোলার ফলে আপনার স্ক্রিপ্টটি কিছু সময়ে থামতে পারে এবং স্মৃতি খায়।
আমির আদনান

4
@ হ্যাঁ, Queueমডিউলটির পুনরায় নামকরণ করা queueহয়েছে পাইথন ৩ This এটি পাইথন 2 কোড।
তার্নে কলমেন

3
আপনি যদি সংযোগ অব্যাহত রেখে প্রতিবার সেম সার্ভারের সাথে কথা বলতে চান তবে আপনি কত দ্রুত যেতে পারেন? এটি কি থ্রেড জুড়েও করা যেতে পারে, বা প্রতিটি থ্রেডের সাথে একটানা সংযোগ দিয়ে করা যেতে পারে?
দুর্দশাগ্রস্ত

2
@ এমপেটভেশন, আপনি যদি সিপিথন ব্যবহার করছেন তবে আপনি (উদাহরণস্বরূপ) "প্রিন্টের স্থিতি, ইউআরএল" "" আমার_গ্লোবাল_লিস্ট.অ্যাপেন্ড ((স্ট্যাটাস, ইউআরএল)) এর সাথে প্রতিস্থাপন করতে পারেন। (বেশিরভাগ ক্রিয়াকলাপে) তালিকাগুলি জিআইএল-এর কারণে সিপিথন (এবং আরও কিছু পাইথন বাস্তবায়ন) স্পষ্টভাবে থ্রেড-নিরাপদ, তাই এটি করা নিরাপদ।
তার্নে কলমেন

54

টর্নেডো অ্যাসিনক্রোনাস নেটওয়ার্কিং লাইব্রেরি ব্যবহার করে একটি সমাধান

from tornado import ioloop, httpclient

i = 0

def handle_request(response):
    print(response.code)
    global i
    i -= 1
    if i == 0:
        ioloop.IOLoop.instance().stop()

http_client = httpclient.AsyncHTTPClient()
for url in open('urls.txt'):
    i += 1
    http_client.fetch(url.strip(), handle_request, method='HEAD')
ioloop.IOLoop.instance().start()

7
এই কোডটি অ-ব্লকিং নেটওয়ার্ক I / O ব্যবহার করছে এবং এতে কোনও বাধা নেই। এটি কয়েক হাজার খোলা সংযোগে স্কেল করতে পারে। এটি একক থ্রেডে চলবে তবে কোনও থ্রেডিং সমাধানের পরে দ্রুততর হবে। চেকআউট অ ব্লক ইনপুট / আউটপুট en.wikipedia.org/wiki/Asynchronous_I/O
mher

1
আপনি এখানে গ্লোবাল আই ভেরিয়েবলের সাথে কী ঘটছে তা ব্যাখ্যা করতে পারেন? কিছু ধরণের ত্রুটি পরীক্ষা করা?
লিটলববি টেবিলগুলি

4
`` Olo `` exit determin - কখন আপনার কাজ শেষ হয় তা নির্ধারণের জন্য এটি একটি পাল্টা।
মাইকেল ডোনার

1
@ অ্যান্ড্রুস্কট এভানস অনুসারে এটি ধরে নেওয়া হয়েছে যে আপনি পাইথন ২.7 এবং প্রক্সি ব্যবহার করছেন
দেজেল

5
@ গুয়ি অভ্রাহাম আপনার ডিডোস পরিকল্পনায় সহায়তার জন্য সৌভাগ্য কামনা করছি।
ওয়াল্টার

51

২০১০ সাল থেকে বিষয়গুলি বেশ কিছুটা পরিবর্তিত হয়েছে যখন এটি পোস্ট করা হয়েছিল এবং আমি অন্যান্য সমস্ত উত্তর চেষ্টা করে দেখিনি তবে আমি কয়েকটি চেষ্টা করেছি এবং পাইথন ৩..6 ব্যবহার করে এটি আমার পক্ষে সবচেয়ে ভাল কাজ করার বিষয়টি খুঁজে পেয়েছি।

আমি প্রতি ডাব্লুএসএসে প্রতি সেকেন্ডে প্রায় 150 ডলার অনন্য ডোমেন আনতে সক্ষম হয়েছি।

import pandas as pd
import concurrent.futures
import requests
import time

out = []
CONNECTIONS = 100
TIMEOUT = 5

tlds = open('../data/sample_1k.txt').read().splitlines()
urls = ['http://{}'.format(x) for x in tlds[1:]]

def load_url(url, timeout):
    ans = requests.head(url, timeout=timeout)
    return ans.status_code

with concurrent.futures.ThreadPoolExecutor(max_workers=CONNECTIONS) as executor:
    future_to_url = (executor.submit(load_url, url, TIMEOUT) for url in urls)
    time1 = time.time()
    for future in concurrent.futures.as_completed(future_to_url):
        try:
            data = future.result()
        except Exception as exc:
            data = str(type(exc))
        finally:
            out.append(data)

            print(str(len(out)),end="\r")

    time2 = time.time()

print(f'Took {time2-time1:.2f} s')
print(pd.Series(out).value_counts())

1
আমি কেবল জিজ্ঞাসা করছি কারণ আমি জানি না তবে এই ফিউচার স্টাফগুলি async / প্রতীক্ষার সাথে প্রতিস্থাপন করা যেতে পারে?
ট্যানকোরস্যামশ

1
এটি পারে, তবে আমি আরও ভাল কাজ করার জন্য উপরেরটি খুঁজে পেয়েছি। আপনি আইওএইচটিপি ব্যবহার করতে পারেন তবে এটি স্ট্যান্ডার্ড লিবের অংশ নয় এবং বেশ পরিবর্তন হচ্ছে। এটি কাজ করে তবে আমি এটি কাজ করতে পাইনি। আমি যখন এটি ব্যবহার করি তখন আমার উচ্চ ত্রুটির হার পাওয়া যায় এবং আমার জীবনের জন্য আমি এটি একই সাথে কাজ করতে পারি না একই সাথে সাম্প্রতিক ফিউচারগুলি যদিও তাত্ত্বিকভাবে মনে হয় এটি আরও ভাল কাজ করা উচিত, দেখুন: stackoverflow.com/questions/45800857/… যদি আপনি এটি ভালভাবে কাজ করতে পান তবে আপনার উত্তর পোস্ট করুন যাতে আমি এটি পরীক্ষা করতে পারি।
গ্লেন থম্পসন

1
এটি একটি নিটপিক, তবে আমি মনে করি এটি time1 = time.time()লুপের জন্য শীর্ষে এবং লুপের time2 = time.time()ডানদিকের পরে ডানদিকে রেখে দেওয়া অনেক পরিষ্কার ।
ম্যাট এম

আমি আপনার স্নিপেট পরীক্ষা করেছি, এটি কোনওভাবে দু'বার কার্যকর হয়। আমি কি ভুল কিছু করছি? নাকি দুবার চালানো মানে? যদি এটি পরবর্তী ক্ষেত্রে হয়, আপনি কীভাবে এটি দু'বার ট্রিগার করেন তা বুঝতে আপনি আমাকে সহায়তা করতে পারেন?
রনি

1
এটি দু'বার চালানো উচিত নয়। আপনি কেন এটি দেখছেন তা নিশ্চিত নয়।
গ্লেন থম্পসন

40

থ্রেডগুলি এখানে একেবারে উত্তর নয়। তারা প্রক্রিয়া এবং কার্নেল বাধা উভয়ই সরবরাহ করবে, পাশাপাশি থ্রুপুট সীমাগুলিও যদি গ্রহণযোগ্য না তবে সামগ্রিক লক্ষ্য "দ্রুততম উপায়" হয়।

এর সামান্য twistedবিস্তৃত এবং এর অ্যাসিনক্রোনাস HTTPক্লায়েন্ট আপনাকে আরও ভাল ফলাফল দেবে।


আয়রনফোগি: আমি আপনার অনুভূতির দিকে ঝুঁকছি। আমি আমার সমাধানটি থ্রেড এবং সারিগুলির সাথে (স্বয়ংক্রিয় মিউটেক্সগুলির জন্য) প্রয়োগ করার চেষ্টা করেছি, তবে আপনি কী কল্পনা করতে পারেন যে 100,000 জিনিস নিয়ে একটি সারিটি তৈরি করতে কত সময় লাগে ?? আমি এখনও এই থ্রেডে প্রত্যেকের দ্বারা বিভিন্ন বিকল্প এবং পরামর্শ নিয়ে ঘুরে বেড়াচ্ছি, এবং সম্ভবত টুইস্টটি একটি ভাল সমাধান হবে।
ইগরগানাপলস্কি

2
আপনি 100k জিনিস দিয়ে একটি সারি পপুলেশন এড়াতে পারবেন। আপনার ইনপুট থেকে একবারে আইটেমগুলি একবারে প্রক্রিয়া করুন, তারপরে প্রতিটি আইটেমের সাথে অনুরোধ অনুরোধটি প্রক্রিয়াকরণের জন্য একটি থ্রেড চালু করুন। (আমি নীচে বর্ণনা হিসাবে, HTTP অনুরোধ থ্রেড শুরু করার জন্য যখন আপনার সুতোর সংখ্যা কিছু থ্রেশহোল্ড নিচে একটি লঞ্চার থ্রেড ব্যবহার থ্রেড প্রতিক্রিয়া, বা একটি তালিকা সংযোজন tuples করার জন্য একটি অভি ম্যাপিং URL টি ছড়িয়ে ফলাফল লিখতে করুন।।)
এরিক গ্যারিসন

আয়রনফোগি: এছাড়াও, পাইথনের থ্রেড ব্যবহার করে আপনি কোন বাধা পেয়েছেন তা সম্পর্কে আমি আগ্রহী? এবং পাইথন থ্রেডগুলি ওএস কার্নেলের সাথে কীভাবে যোগাযোগ করে?
এরিক গ্যারিসন

নিশ্চিত করুন যে আপনি এপল চুল্লিটি ইনস্টল করেছেন; অন্যথায় আপনি নির্বাচন / পোল ব্যবহার করবেন এবং এটি খুব ধীর হবে। এছাড়াও, যদি আপনি বাস্তবে একই সাথে 100,000 সংযোগ খোলার চেষ্টা করতে যাচ্ছেন (ধরে নিবেন যে আপনার প্রোগ্রামটি সেভাবে লেখা আছে, এবং URL গুলি বিভিন্ন সার্ভারে রয়েছে) তবে আপনাকে আপনার ওএস টিউন করতে হবে যাতে আপনার সঞ্চালন না ঘটে won't ফাইল বর্ণনাকারী, সাময়িক বন্দর ইত্যাদি। (আপনার কাছে একবারে 10,000 অসামান্য সংযোগ নেই বলে নিশ্চিত হওয়া সহজ যে এটি সম্ভবত সহজ)।
মার্ক নটিংহাম

এরিকগ: আপনি দুর্দান্ত ধারণা দেওয়ার পরামর্শ দিয়েছেন। তবে, 200 টি থ্রেড সহ আমি যে সর্বোত্তম ফলাফলটি অর্জন করতে পেরেছিলাম তা প্রায় ছিল। 6 মিনিট। আমি নিশ্চিত যে কম সময়ে এটি সম্পাদন করার উপায় আছে ... মার্ক এন: যদি টুইস্টেড হয়ে যাওয়ার উপায়টি হয়, তবে এপল চুল্লী অবশ্যই কার্যকর। তবে, যদি আমার স্ক্রিপ্টটি একাধিক মেশিন থেকে চালানো হবে, তবে কি প্রতিটি মেশিনে টুইস্টেড ইনস্টল করার প্রয়োজন হবে না? আমি জানি না যে আমি আমার বসকে সেই পথে যেতে রাজি করতে পারি কিনা ...
IgorGanapolsky

21

আমি জানি এটি একটি পুরানো প্রশ্ন, তবে পাইথন ৩.7 এ আপনি asyncioএবং এটি ব্যবহার করে এটি করতে পারেন aiohttp

import asyncio
import aiohttp
from aiohttp import ClientSession, ClientConnectorError

async def fetch_html(url: str, session: ClientSession, **kwargs) -> tuple:
    try:
        resp = await session.request(method="GET", url=url, **kwargs)
    except ClientConnectorError:
        return (url, 404)
    return (url, resp.status)

async def make_requests(urls: set, **kwargs) -> None:
    async with ClientSession() as session:
        tasks = []
        for url in urls:
            tasks.append(
                fetch_html(url=url, session=session, **kwargs)
            )
        results = await asyncio.gather(*tasks)

    for result in results:
        print(f'{result[1]} - {str(result[0])}')

if __name__ == "__main__":
    import pathlib
    import sys

    assert sys.version_info >= (3, 7), "Script requires Python 3.7+."
    here = pathlib.Path(__file__).parent

    with open(here.joinpath("urls.txt")) as infile:
        urls = set(map(str.strip, infile))

    asyncio.run(make_requests(urls=urls))

আপনি এটি সম্পর্কে আরও পড়তে পারেন এবং এখানে একটি উদাহরণ দেখতে পারেন ।


এটি কি সি # অ্যাসিঙ্ক / প্রতীক্ষা এবং কোটলিন কর্টিনগুলির সাথে সমান?
ইগোরগানাপলস্কি

@ ইগোরগানাপলস্কি, হ্যাঁ, এটি সি # অ্যাসিঙ্ক / প্রতীক্ষার সাথে খুব মিল similar আমি কোটলিন করোটিনগুলির সাথে পরিচিত নই।
মারিয়াস স্টেনেস্কু

@ সানডাইপ, আমি নিশ্চিত না যে এটি কাজ করে কিনা, তবে আপনি যদি চেষ্টা করতে চান তবে আপনাকে আইওএইচটিটিপির জন্য ইউনিক্স সংযোগকারী ব্যবহার করতে হবে। এখানে আরও পড়ুন: docs.aiohttp.org/en/stable/client_references.html#connectors
মারিয়াস স্টেনেসু

ধন্যবাদ @ মারিয়াসস্টেসেকু। ঠিক এটাই আমি ব্যবহার করেছি।
স্যান্ডপ

Asyncio.gather (* কার্য) দেখানোর জন্য +1। এখানে এমন একটি স্নিপেট যা আমি ব্যবহার করেছি: urls= [fetch(construct_fetch_url(u),idx) for idx, u in enumerate(some_URI_list)] results = await asyncio.gather(*urls)
অশ্বিনী কুমার

19

গ্রুয়েস্ট ব্যবহার করুন , এটি অনুরোধগুলির + জেনভেন্ট মডিউলগুলির সংমিশ্রণ।

গ্রিকয়েস্টগুলি আপনাকে সহজেই অ্যাসক্রোনাস এইচটিটিপি অনুরোধ করতে জেন্টের সাথে অনুরোধগুলি ব্যবহার করতে দেয়।

ব্যবহার সহজ:

import grequests

urls = [
   'http://www.heroku.com',
   'http://tablib.org',
   'http://httpbin.org',
   'http://python-requests.org',
   'http://kennethreitz.com'
]

না পাঠানো অনুরোধের একটি সেট তৈরি করুন:

>>> rs = (grequests.get(u) for u in urls)

তাদের একই সময়ে পাঠান:

>>> grequests.map(rs)
[<Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>]


14
গ্রায়েস্টগুলি সাধারণ অনুরোধের অংশ নয় এবং মনে হয় এটি বেশিরভাগই শৌখিন
থম

8

এই সমস্যা সমাধানের জন্য একটি ভাল পদ্ধতির হ'ল প্রথমে একটি ফলাফল পাওয়ার জন্য প্রয়োজনীয় কোডটি লিখতে হবে, তারপরে অ্যাপ্লিকেশনটির সমান্তরাল করতে থ্রেডিং কোড অন্তর্ভুক্ত করতে হবে।

নিখুঁত বিশ্বে এটি কেবল একই সাথে 100,000 থ্রেডগুলি শুরু করে যা পরবর্তী ফলাফলগুলি প্রক্রিয়াকরণের জন্য তাদের ফলাফলকে একটি অভিধান বা তালিকায় আউটপুট দেয় তবে বাস্তবে আপনি কতটা সমান্তরাল এইচটিটিপি অনুরোধে এই ফ্যাশনে ইস্যু করতে পারবেন তা সীমাবদ্ধ। স্থানীয়ভাবে, আপনার এক সাথে কতগুলি সকেট খুলতে পারে তার সীমাবদ্ধতা রয়েছে, আপনার পাইথন ইন্টারপ্রেটার কতগুলি মৃত্যুদন্ড কার্যকর করতে পারবেন। দূরবর্তীভাবে, সমস্ত অনুরোধগুলি একটি সার্ভারের বিরুদ্ধে, বা অনেকের বিরুদ্ধে থাকলে আপনি একযোগে সংযোগের সংখ্যায় সীমাবদ্ধ থাকতে পারেন। এই সীমাবদ্ধতাগুলির সম্ভবত সম্ভবত আপনি স্ক্রিপ্টটি এমনভাবে রচনা করবেন যাতে কোনও এক সময় কেবলমাত্র ইউআরএলগুলির একটি ক্ষুদ্র ভগ্নাংশটি পোল করতে হয় (100, উল্লিখিত অন্য পোস্টার হিসাবে সম্ভবত একটি শালীন পুলের আকার, যদিও আপনি দেখতে পাচ্ছেন যে আপনি সাফল্যের সাথে আরও অনেকগুলি মোতায়েন করতে পারে)।

উপরের সমস্যাটি সমাধান করতে আপনি এই নকশার ধরণটি অনুসরণ করতে পারেন:

  1. থ্রেড শুরু করুন যা বর্তমানে চলমান থ্রেডগুলির সংখ্যা পর্যন্ত নতুন অনুরোধের থ্রেডগুলি প্রবর্তন করে (আপনি থ্রেডিং.এ্যাকটিভ_কাউন্টের মাধ্যমে তাদের ট্র্যাক করতে পারেন) বা থ্রেডের বিষয়গুলিকে একটি ডেটা স্ট্রাকচারে ঠেলে দিয়ে) = = আপনার একযোগে অনুরোধের সর্বোচ্চ সংখ্যা (100 বলুন) , তারপরে অল্প সময়ের জন্য ঘুমায়। প্রক্রিয়া করার জন্য আর কোনও URL থাকে না তখন এই থ্রেডটি সমাপ্ত করা উচিত। সুতরাং, থ্রেড জেগে থাকবে, নতুন থ্রেড চালু করবে এবং আপনার সমাপ্ত হওয়া অবধি ঘুমিয়ে থাকবে।
  2. অনুরোধের থ্রেডগুলি পরবর্তী ফলাফল এবং ফলাফলের জন্য কিছু ফলাফল কাঠামোতে তাদের ফলাফলগুলি সংরক্ষণ করে। আপনি যে কাঠামোটিতে ফলাফলগুলি সংরক্ষণ করছেন তা যদি হয় listবা dictসিপাইটিতে থাকে তবে আপনি সুরক্ষিতভাবে লক ছাড়াই আপনার থ্রেড থেকে অনন্য আইটেম সংযোজন বা সন্নিবেশ করতে পারেন , তবে আপনি যদি কোনও ফাইলে লিখেন বা আরও জটিল ক্রস-থ্রেড ডেটা ইন্টারঅ্যাকশন প্রয়োজন হয় তবে আপনাকে একটি ব্যবহার করতে হবে এই রাষ্ট্রকে দুর্নীতির হাত থেকে রক্ষা করতে পারস্পরিক বর্জনীয় লক

আমি আপনাকে থ্রেডিং মডিউলটি ব্যবহার করার পরামর্শ দেব । চলমান থ্রেডগুলি চালু এবং ট্র্যাক করতে আপনি এটি ব্যবহার করতে পারেন। পাইথনের থ্রেডিং সমর্থনটি খালি তবে আপনার সমস্যার বর্ণনা থেকে বোঝা যায় যে এটি আপনার প্রয়োজনের জন্য পুরোপুরি যথেষ্ট।

অবশেষে, আপনি পাইথনে লিখিত সমান্তরাল নেটওয়ার্ক অ্যাপ্লিকেশনটির জন্য একটি দুর্দান্ত সোজা অ্যাপ্লিকেশন দেখতে চাইলে ssh.py দেখুন । এটি একটি ছোট গ্রন্থাগার যা বহু এসএসএইচ সংযোগকে সমান্তরালে পাইথন থ্রেডিং ব্যবহার করে। ডিজাইনটি আপনার প্রয়োজনীয়তার কাছে যথেষ্ট পরিমাণে রয়েছে যা আপনি এটি একটি ভাল সংস্থান হিসাবে খুঁজে পেতে পারেন।


1
এরিকগ: আপনার সমীকরণের মধ্যে একটি সারিতে নিক্ষেপ করা কি যুক্তিসঙ্গত হবে (পারস্পরিক-বাদ দেওয়ার লক করার জন্য)? আমি সন্দেহ করি পাইথনের জিআইএল হাজার হাজার থ্রেড নিয়ে খেলতে আগ্রহী নয়।
ইগরগানাপলস্কি

খুব বেশি থ্রেড তৈরি করা রোধ করতে আপনার কেন পারস্পরিক-বর্জনীয় লকিং দরকার? আমার সন্দেহ হয় আমি এই শব্দটিকে ভুল বুঝি। আপনি থ্রেড কাতারে চলমান থ্রেডগুলি ট্র্যাক করতে পারেন, সেগুলি শেষ হয়ে গেলে সেগুলি সরিয়ে এবং থ্রেড সীমাতে আরও যোগ করে। তবে সাধারণ প্রশ্নে যেমন আপনি এখনকার পাইথন প্রসেসে সক্রিয় থ্রেডের সংখ্যাটি কেবল দেখতে পারেন, এটি একটি প্রান্তিকের নীচে না আসা পর্যন্ত অপেক্ষা করুন এবং বর্ণনাক্রমে আরও থ্রেডহোল্ড শুরু করতে পারেন। আমি অনুমান করি আপনি এটি একটি অন্তর্নিহিত লক বিবেচনা করতে পারেন, কিন্তু কোন স্পষ্টত লক প্রয়োজন হয় না।
এরিক গ্যারিসন

এরিকগ: একাধিক থ্রেডের রাজ্য ভাগ হয় না? ওরিলির গ্রন্থ "ইউনিক্স এবং লিনাক্স সিস্টেম প্রশাসনের জন্য পাইথন" বইয়ের 305 পৃষ্ঠায় এটি উল্লেখ করেছে: "... কাতারি না করে থ্রেডিং ব্যবহার করা অনেকগুলি বাস্তবসম্মতভাবে পরিচালনা করতে পারে তার চেয়ে জটিল করে তোলে always সারিবদ্ধভাবে সর্বদা ব্যবহার করা আরও অনেক ভাল ধারণা is মডিউল যদি আপনার মনে হয় যে থ্রেডগুলি ব্যবহার করা দরকার Why কেন? কেননা কিউ মডিউলটি স্পষ্টরূপে মুটেক্সগুলির সাহায্যে ডেটা সুরক্ষিত করার প্রয়োজনীয়তাও হ্রাস করে কারণ সারিটি ইতিমধ্যে একটি মিউটেক্স দ্বারা অভ্যন্তরীণভাবে সুরক্ষিত "" আবার, আমি এই বিষয়ে আপনার দৃষ্টিভঙ্গি স্বাগত জানাই।
ইগোরগানাপলস্কি

ইগর: আপনি একেবারে ঠিক বলেছেন যে আপনার একটি লক ব্যবহার করা উচিত। এটি প্রতিফলিত করার জন্য আমি পোস্টটি সম্পাদনা করেছি। এটি বলে, অজগর নিয়ে ব্যবহারিক অভিজ্ঞতা থেকে বোঝা যায় যে আপনার থ্রেডগুলি থেকে আপনি পরমাণুগতভাবে সংশোধন করেছেন এমন ডেটা স্ট্রাকচারগুলি লক করার দরকার নেই যেমন তালিকা.অ্যাপেন্ড বা হ্যাশ কী যোগ করার মাধ্যমে। আমি বিশ্বাস করি যে কারণটি হ'ল জিআইএল, যা কিছু পরিমাণে পারমাণবিকতার সাথে তালিকা.অপেন্ডের মতো ক্রিয়াকলাপ সরবরাহ করে। এটি যাচাই করার জন্য আমি বর্তমানে একটি পরীক্ষা চালিয়ে যাচ্ছি (তালিকায় 0-9999 নম্বর সংযুক্ত করতে 10 কে থ্রেড ব্যবহার করুন, সমস্ত পরিশ্রম কাজ করেছে কিনা তা পরীক্ষা করে দেখুন)। প্রায় 100 টি পুনরাবৃত্তির পরেও পরীক্ষা ব্যর্থ হয়নি।
এরিক গ্যারিসন

ইগর: আমাকে এই বিষয়ে আরও একটি প্রশ্ন জিজ্ঞাসা করা হয়েছে: স্ট্যাকওভারফ্লো
এরিক গ্যারিসন

7

আপনি যদি সেরা পারফরম্যান্সের সম্ভাব্যতা অর্জন করতে চাইছেন তবে আপনি থ্রেডের চেয়ে অ্যাসিঙ্ক্রোনাস আই / ও ব্যবহার করার বিষয়টি বিবেচনা করতে পারেন। হাজার হাজার ওএস থ্রেডের সাথে যুক্ত ওভারহেড অপ্রয়োজনীয় এবং পাইথন ইন্টারপ্রেটারের মধ্যে প্রসঙ্গের স্যুইচিং এর উপরে আরও যুক্ত করে। থ্রেডিং অবশ্যই কাজটি সম্পন্ন করবে তবে আমি সন্দেহ করি যে একটি অ্যাসিনক্রোনাস রুট আরও ভাল সামগ্রিক কর্মক্ষমতা সরবরাহ করবে।

বিশেষত, আমি ট্যুইস্টেড লাইব্রেরিতে অ্যাসিঙ্ক ওয়েব ক্লায়েন্টকে পরামর্শ দেব ( http://www.twistedmatrix.com )। এটিতে স্বীকৃতভাবে খাড়া শেখার বক্ররেখা রয়েছে তবে একবারে আপনি টুইঙ্কেড স্টাইল অ্যাসিঙ্ক্রোনাস প্রোগ্রামিংয়ের একটি ভাল হ্যান্ডেল পেয়ে গেলে এটি ব্যবহার করা বেশ সহজ।

টুইস্টেড অ্যাসিঙ্ক্রোনাস ওয়েব ক্লায়েন্ট API এ একটি হাওটো এখানে পাওয়া যায়:

http://twistedmatrix.com/documents/current/web/howto/client.html


রাকিস: আমি বর্তমানে অ্যাসিনক্রোনাস এবং অ-ব্লকিং আই / ও-তে সন্ধান করছি। আমি এটি প্রয়োগ করার আগে এটি আরও ভাল করে শেখা দরকার। আমি আপনার পোস্টে একটি মন্তব্য করতে চাই যে "হাজার হাজার ওএস থ্রেড" তৈরি করা অসম্ভব (কমপক্ষে আমার লিনাক্স বিতরণের অধীনে)। প্রোগ্রামটি ভাঙ্গার আগে পাইথন আপনাকে সর্বাধিক সংখ্যক থ্রেড সরবরাহ করতে দেবে। এবং আমার ক্ষেত্রে (CentOS 5 এ) সর্বাধিক সংখ্যার থ্রেড 303
IgorGanapolsky

এটা জানা ভাল. আমি পাইথনে মুষ্টিমেয় কিছু বেশি একবারে একবারে চেষ্টা করার চেষ্টা করি নি তবে এটি বোমা ফাটার আগে আমি এর থেকে আরও বেশি কিছু তৈরি করতে সক্ষম হতে পারব বলে আশা করি।
রাকিস 3'10

6

একটি সমাধান:

from twisted.internet import reactor, threads
from urlparse import urlparse
import httplib
import itertools


concurrent = 200
finished=itertools.count(1)
reactor.suggestThreadPoolSize(concurrent)

def getStatus(ourl):
    url = urlparse(ourl)
    conn = httplib.HTTPConnection(url.netloc)   
    conn.request("HEAD", url.path)
    res = conn.getresponse()
    return res.status

def processResponse(response,url):
    print response, url
    processedOne()

def processError(error,url):
    print "error", url#, error
    processedOne()

def processedOne():
    if finished.next()==added:
        reactor.stop()

def addTask(url):
    req = threads.deferToThread(getStatus, url)
    req.addCallback(processResponse, url)
    req.addErrback(processError, url)   

added=0
for url in open('urllist.txt'):
    added+=1
    addTask(url.strip())

try:
    reactor.run()
except KeyboardInterrupt:
    reactor.stop()

Testtime:

[kalmi@ubi1:~] wc -l urllist.txt
10000 urllist.txt
[kalmi@ubi1:~] time python f.py > /dev/null 

real    1m10.682s
user    0m16.020s
sys 0m10.330s
[kalmi@ubi1:~] head -n 6 urllist.txt
http://www.google.com
http://www.bix.hu
http://www.godaddy.com
http://www.google.com
http://www.bix.hu
http://www.godaddy.com
[kalmi@ubi1:~] python f.py | head -n 6
200 http://www.bix.hu
200 http://www.bix.hu
200 http://www.bix.hu
200 http://www.bix.hu
200 http://www.bix.hu
200 http://www.bix.hu

Pingtime:

bix.hu is ~10 ms away from me
godaddy.com: ~170 ms
google.com: ~30 ms

6
থ্রেডপুল হিসাবে টুইস্ট ব্যবহার করা আপনি এর থেকে পেতে পারেন এমন বেশিরভাগ সুবিধা উপেক্ষা করছেন। পরিবর্তে আপনার async HTTP ক্লায়েন্ট ব্যবহার করা উচিত।
জিন-পল ক্যালডেরন

1

থ্রেড পুল ব্যবহার করা একটি ভাল বিকল্প, এবং এটি মোটামুটি সহজ করে তুলবে। দুর্ভাগ্যক্রমে, পাইথনের স্ট্যান্ডার্ড পুলগুলিকে অতি সহজ করে তোলে এমন একটি স্ট্যান্ডার্ড লাইব্রেরি নেই। তবে এখানে একটি শালীন গ্রন্থাগার রয়েছে যা আপনাকে শুরু করা উচিত: http://www.chrisarndt.de/projects/threadpool/

কোডের উদাহরণটি তাদের সাইট থেকে:

pool = ThreadPool(poolsize)
requests = makeRequests(some_callable, list_of_args, callback)
[pool.putRequest(req) for req in requests]
pool.wait()

আশাকরি এটা সাহায্য করবে.


আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি থ্রেডপুলের জন্য এই জাতীয় q_size নির্দিষ্ট করুন: থ্রেডপুল (পুলসাইজ, কি_সাইজ = 1000) যাতে আপনার মেমোরিতে 100000 ওয়ার্কেরউকেস্ট অবজেক্ট না থাকে। "যদি q_size> 0 কাজের অনুরোধের সারির আকার সীমাবদ্ধ থাকে এবং কাতার পূর্ণ হয়ে যায় তখন থ্রেড পুল ব্লক হয়ে যায় এবং এটি এতে আরও কাজের অনুরোধগুলি রাখার চেষ্টা করে ( putRequestপদ্ধতিটি দেখুন), যদি না আপনি এর timeoutজন্য ইতিবাচক মানও ব্যবহার করেন putRequest।"
তারনে কলমেন

এখন পর্যন্ত আমি থ্রেডপুল সমাধানটি প্রয়োগ করার চেষ্টা করছি - যেমনটি পরামর্শ দেওয়া হয়েছে। তবে আমি মেকআরকুইয়েস্টস ফাংশনে প্যারামিটার তালিকাটি বুঝতে পারি না। কিছু_আপনিযোগ্য, তালিকা_ের_আর্গস, কলব্যাক কী? সম্ভবত যদি আমি একটি বাস্তব কোড স্নিপেট দেখেছি যা সাহায্য করবে। আমি অবাক হয়েছি যে library গ্রন্থাগারের লেখক কোনও উদাহরণ পোস্ট করেন নি।
ইগোরগানাপলস্কি

some_callable হ'ল আপনার ফাংশন যা আপনার সমস্ত কাজ (HTTP সার্ভারের সাথে সংযোগ স্থাপন) এ সম্পন্ন হয়েছে। list_of_args হল আর্গুমেন্ট যা কোনও_ক্যাল্যাবে যাবে। কলব্যাক একটি ফাংশন যা কর্মী থ্রেড হয়ে গেলে ডাকা হবে। এটি দুটি যুক্তি গ্রহণ করে, শ্রমিক আপত্তি (আপনার সত্যিকারের সাথে এটি নিয়ে নিজেকে উদ্বিগ্ন করার দরকার নেই), এবং কর্মী পুনরুদ্ধার করে।
কেভিন উইস্কিয়া

1

তৈরি করুন epollবস্তু,
খোলা অনেক ক্লায়েন্ট বিভিন্ন TCP সকেট,
অনুরোধ শীর্ষক চেয়ে একটি বিট আরো হতে তাদের পাঠাতে বাফার সমন্বয়
একটি অনুরোধ হেডার পাঠাতে - এটা অবিলম্বে হওয়া উচিত শুধু একটি বাফার মধ্যে স্থাপন করে, নিবন্ধন সকেট epollবস্তু,
না .pollউপর epollobect,
প্রথম পড়া 3 প্রতিটি সকেট থেকে বাইটস .poll,
সেগুলি sys.stdoutঅনুসরণ করে \n(ফ্লাশ করবেন না) ক্লায়েন্ট সকেটটি বন্ধ করুন।

সকেটের এক সাথে সীমাবদ্ধতার সংখ্যা সীমাবদ্ধ করুন - সকেটগুলি তৈরি করার সময় ত্রুটিগুলি পরিচালনা করুন। অন্যটি বন্ধ থাকলেই একটি নতুন সকেট তৈরি করুন।
ওএস সীমা সামঞ্জস্য করুন।
কয়েকটি (অনেকগুলি নয়) প্রক্রিয়াগুলিতে জালিয়াতির চেষ্টা করুন: এটি সিপিইউকে আরও কার্যকরভাবে ব্যবহার করতে সহায়তা করতে পারে।


@ আইগরগানাপলস্কি অবশ্যই হবে। আমি অন্যথায় অবাক হতে হবে। তবে এটি অবশ্যই পরীক্ষামূলক প্রয়োজন।
জর্জ সোভেটোভ

0

আপনার ক্ষেত্রে থ্রেডিং সম্ভবত কৌশলটি করবে কারণ আপনি সম্ভবত বেশিরভাগ সময় সাড়া দেওয়ার জন্য অপেক্ষা করতে যাবেন। স্ট্যান্ডার্ড লাইব্রেরিতে কুইয়ের মতো সহায়ক মডিউল রয়েছে যা সহায়তা করতে পারে।

আমি আগে ফাইলগুলি সমান্তরাল ডাউনলোড করার সাথে একই জিনিস করেছি এবং এটি আমার পক্ষে যথেষ্ট ভাল, তবে আপনি যে স্কেলটির বিষয়ে কথা বলছেন তা সেটি ছিল না।

যদি আপনার টাস্কটি আরও সিপিইউযুক্ত ছিল, আপনি মাল্টিপ্রসেসিং মডিউলটি দেখতে চাইতে পারেন , যা আপনাকে আরও সিপিইউ / কোর / থ্রেড ব্যবহার করতে দেয় (আরও প্রক্রিয়া যা একে অপরকে অবরুদ্ধ করবে না যেহেতু লক প্রক্রিয়া অনুযায়ী প্রক্রিয়া চলছে)


কেবলমাত্র আমি উল্লেখ করতে চাই যে একাধিক প্রক্রিয়া তৈরি করা একাধিক থ্রেড তৈরি করার চেয়ে ব্যয়বহুল। এছাড়াও, একাধিক প্রক্রিয়া বনাম একাধিক থ্রেড সহ 100,000 এইচটিটিপি অনুরোধগুলি প্রেরণে কোনও স্পষ্ট পারফরম্যান্স লাভ নেই।
ইগোরগানাপলস্কি

0

উইন্ডমিল ব্যবহার বিবেচনা করুন , যদিও উইন্ডমিল সম্ভবত এটি অনেক থ্রেড করতে পারে না।

আপনি এটি 5 টি মেশিনে হ্যান্ড রোলড পাইথন স্ক্রিপ্ট দিয়ে করতে পারেন, প্রত্যেকে 10000 পোর্ট সংযোগ খোলার মাধ্যমে 40000-60000 বন্দর ব্যবহার করে বিদেশের সাথে সংযোগ স্থাপন করছে।

এছাড়াও, প্রতিটি সার্ভার কতটা পরিচালনা করতে পারে তার ধারণা পাওয়ার জন্য এটি ওপেনস্টা -র মতো দুর্দান্ত থ্রেডযুক্ত কিউএ অ্যাপ্লিকেশন সহ একটি নমুনা পরীক্ষা করতে সহায়তা করতে পারে।

এছাড়াও, কেবল এলডাব্লুপি :: সংযোগ ক্যাশে ক্লাসের সাহায্যে সহজ পার্ল ব্যবহার করার চেষ্টা করুন। আপনি সম্ভবত আরও কর্মক্ষমতা (আরও সংযোগ) পাবেন।


0

এই বাঁকানো অ্যাসিঙ্ক ওয়েব ক্লায়েন্টটি বেশ দ্রুত চলে।

#!/usr/bin/python2.7

from twisted.internet import reactor
from twisted.internet.defer import Deferred, DeferredList, DeferredLock
from twisted.internet.defer import inlineCallbacks
from twisted.web.client import Agent, HTTPConnectionPool
from twisted.web.http_headers import Headers
from pprint import pprint
from collections import defaultdict
from urlparse import urlparse
from random import randrange
import fileinput

pool = HTTPConnectionPool(reactor)
pool.maxPersistentPerHost = 16
agent = Agent(reactor, pool)
locks = defaultdict(DeferredLock)
codes = {}

def getLock(url, simultaneous = 1):
    return locks[urlparse(url).netloc, randrange(simultaneous)]

@inlineCallbacks
def getMapping(url):
    # Limit ourselves to 4 simultaneous connections per host
    # Tweak this number, but it should be no larger than pool.maxPersistentPerHost 
    lock = getLock(url,4)
    yield lock.acquire()
    try:
        resp = yield agent.request('HEAD', url)
        codes[url] = resp.code
    except Exception as e:
        codes[url] = str(e)
    finally:
        lock.release()


dl = DeferredList(getMapping(url.strip()) for url in fileinput.input())
dl.addCallback(lambda _: reactor.stop())

reactor.run()
pprint(codes)

0

আমি দেখতে পেয়েছি যে tornadoপ্যাকেজটি ব্যবহার করা এটি অর্জনের দ্রুত এবং সহজতম উপায়:

from tornado import ioloop, httpclient, gen


def main(urls):
    """
    Asynchronously download the HTML contents of a list of URLs.
    :param urls: A list of URLs to download.
    :return: List of response objects, one for each URL.
    """

    @gen.coroutine
    def fetch_and_handle():
        httpclient.AsyncHTTPClient.configure(None, defaults=dict(user_agent='MyUserAgent'))
        http_client = httpclient.AsyncHTTPClient()
        waiter = gen.WaitIterator(*[http_client.fetch(url, raise_error=False, method='HEAD')
                                    for url in urls])
        results = []
        # Wait for the jobs to complete
        while not waiter.done():
            try:
                response = yield waiter.next()
            except httpclient.HTTPError as e:
                print(f'Non-200 HTTP response returned: {e}')
                continue
            except Exception as e:
                print(f'An unexpected error occurred querying: {e}')
                continue
            else:
                print(f'URL \'{response.request.url}\' has status code <{response.code}>')
                results.append(response)
        return results

    loop = ioloop.IOLoop.current()
    web_pages = loop.run_sync(fetch_and_handle)

    return web_pages

my_urls = ['url1.com', 'url2.com', 'url100000.com']
responses = main(my_urls)
print(responses[0])

-2

পাইথনের বিল্ট-ইন থ্রেডিং লাইব্রেরিটি ব্যবহার করা সবচেয়ে সহজ উপায়। এগুলি "আসল" / কার্নেল থ্রেড নয় তবে তাদের সমস্যা আছে (সিরিয়ালাইজেশনের মতো), তবে যথেষ্ট ভাল are আপনি একটি সারি ও থ্রেড পুল চাইবেন। এখানে একটি বিকল্প রয়েছে , তবে এটি নিজের লেখার পক্ষে তুচ্ছ। আপনি সমস্ত ১০,০০,০০০ কলকে সমান্তরাল করতে পারবেন না, তবে আপনি একই সময়ে তাদের ১০০ (বা তাই) বন্ধ করতে পারেন।


7
পাইথনের থ্রেডগুলি বেশ বাস্তব, উদাহরণস্বরূপ রুবির বিপরীতে। হুডের নীচে সেগুলি কমপক্ষে ইউনিক্স / লিনাক্স এবং উইন্ডোজে নেটিভ ওএস থ্রেড হিসাবে প্রয়োগ করা হয়। হতে পারে আপনি জিআইএল-কে উল্লেখ করছেন, তবে এটি থ্রেডগুলি কম বাস্তব করে তোলে না ...
এলি বেন্ডারস্কি

2
পাইথনের থ্রেডগুলি সম্পর্কে এলি ঠিক বলেছেন, তবে পেস্টিলেসের বিষয়টি আপনি যে কোনও থ্রেড পুল ব্যবহার করতে চান তাও সঠিক। আপনি এই ক্ষেত্রে শেষ কাজটি করতে চাইছেন তা হ'ল 100 কে অনুরোধের প্রত্যেকটির জন্য এক সাথে আলাদা থ্রেড শুরু করার চেষ্টা করা।
অ্যাডাম ক্রসল্যান্ড

1
ইগোর, আপনি সংজ্ঞায়িতভাবে মন্তব্যে কোড স্নিপেটগুলি পোস্ট করতে পারবেন না, তবে আপনি নিজের প্রশ্নটি সম্পাদনা করতে এবং সেগুলিতে সেখানে যুক্ত করতে পারেন।
অ্যাডাম ক্রসল্যান্ড

মহামারী: আমার সলিউশনের জন্য আপনি কত সারি এবং থ্রেড-প্রতি কাতারে সুপারিশ করবেন?
ইগোরগানাপলস্কি

প্লাস এটি একটি আই / ও বাউন্ড টাস্ক, সিপিইউ বাউন্ড নয়, জিআইএল মূলত সিপিইউ বাউন্ড টাস্কগুলিকে প্রভাবিত করে
পাইরেটএপ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.