Как я могу разбить этот многопоточный скрипт Python на «куски»?

1

Я обрабатываю доменные имена 100k в CSV на основе результатов, полученных с Siteadvisor, используя urllib (не лучший метод, я знаю). Однако мой текущий script создает слишком много потоков, а Python попадает в ошибки. Есть ли способ, которым я могу "обмануть" этот script, чтобы сделать X количество доменов за раз (например, 10-20), чтобы предотвратить эти ошибки? Спасибо заранее.

import threading
import urllib

class Resolver(threading.Thread):
    def __init__(self, address, result_dict):
        threading.Thread.__init__(self)
        self.address = address
        self.result_dict = result_dict

    def run(self):
        try:
            content = urllib.urlopen("http://www.siteadvisor.com/sites/" + self.address).read(12000)
            search1 = content.find("didn't find any significant problems.")
            search2 = content.find('yellow')
            search3 = content.find('web reputation analysis found potential security')
            search4 = content.find("don't have the results yet.")

            if search1 != -1:
                result = "safe"
            elif search2 != -1:
                result = "caution"
            elif search3 != -1:
                result = "warning"
            elif search4 != -1:
                result = "unknown"
            else:
                result = ""

            self.result_dict[self.address] = result

        except:
            pass


def main():
    infile = open("domainslist", "r")
    intext = infile.readlines()
    threads = []
    results = {}
    for address in [address.strip() for address in intext if address.strip()]:
        resolver_thread = Resolver(address, results)
        threads.append(resolver_thread)
        resolver_thread.start()

    for thread in threads:
        thread.join()

    outfile = open('final.csv', 'w')
    outfile.write("\n".join("%s,%s" % (address, ip) for address, ip in results.iteritems()))
    outfile.close()

if __name__ == '__main__':
    main()

Изменить: новая версия на основе предложений andyortlieb.

import threading
import urllib
import time

class Resolver(threading.Thread):
    def __init__(self, address, result_dict, threads):
        threading.Thread.__init__(self)
        self.address = address
        self.result_dict = result_dict
        self.threads = threads
    def run(self):
        try:
            content = urllib.urlopen("http://www.siteadvisor.com/sites/" + self.address).read(12000)
            search1 = content.find("didn't find any significant problems.")
            search2 = content.find('yellow')
            search3 = content.find('web reputation analysis found potential security')
            search4 = content.find("don't have the results yet.")

            if search1 != -1:
                result = "safe"
            elif search2 != -1:
                result = "caution"
            elif search3 != -1:
                result = "warning"
            elif search4 != -1:
                result = "unknown"
            else:
                result = ""

            self.result_dict[self.address] = result

            outfile = open('final.csv', 'a')
            outfile.write(self.address + "," + result + "\n")
            outfile.close()
            print self.address + result

            threads.remove(self)
        except:
            pass


def main():
    infile = open("domainslist", "r")
    intext = infile.readlines()
    threads = []
    results = {}

    for address in [address.strip() for address in intext if address.strip()]:
        loop=True
        while loop:
            if len(threads) < 20:
                resolver_thread = Resolver(address, results, threads)
                threads.append(resolver_thread)
                resolver_thread.start()
                loop=False
            else:
                time.sleep(.25)


    for thread in threads:
        thread.join()

#    removed so I can track the progress of the script
#    outfile = open('final.csv', 'w')
#    outfile.write("\n".join("%s,%s" % (address, ip) for address, ip in results.iteritems()))
#    outfile.close()

if __name__ == '__main__':
     main()
Теги:
python-multithreading

2 ответа

2
Лучший ответ

Это может быть довольно жестко, но вы можете передавать потоки в Resolver, так что, когда Resolver.run завершен, он может вызывать thread.remove(self)

Затем вы можете вложить некоторые условия, чтобы потоки создавались только в том случае, если есть место для них, и если их нет, они ждут, пока они не появятся.

for address in [address.strip() for address in intext if address.strip()]:
        loop=True
        while loop:
            if len(threads)<20:
                resolver_thread = Resolver(address, results, threads)
                threads.append(resolver_thread)
                resolver_thread.start()
                loop=False
            else: 
                time.sleep(.25)
  • 0
    Спасибо за вашу помощь. Я реализовал ваши изменения. Однако скрипт получает только до 20 доменов. Я поставил свой сценарий выше. Вы знаете, в чем проблема?
  • 0
    Я считаю, что все, что вам нужно, это изменить threads.remove (self) на self.threads.remove (self)
Показать ещё 3 комментария
2

Ваш существующий код будет работать красиво - просто измените свой метод __init__ внутри Resolver, чтобы принять дополнительный список адресов вместо одного, поэтому вместо того, чтобы иметь один поток для каждого адреса, у вас есть один поток на каждые 10 (например). Таким образом, вы не будете перегружать потоки.

Очевидно, вам придется слегка изменить run, чтобы он пересекал массив адресов вместо одного self.address.

Я могу выполнить быстрый пример, если вы хотите, но из-за качества вашего кода мне кажется, что вы сможете легко справиться с этим.

Надеюсь, это поможет!

РЕДАКТИРОВАТЬ Пример ниже в соответствии с запросом. Обратите внимание, что вам нужно будет изменить main, чтобы отправлять списки адресов экземпляров Resolver вместо одного адреса - я не мог справиться с этим для вас, не зная больше о формате вашего файла и способах сохранения адресов. Примечание. Вы можете использовать метод run со вспомогательной функцией, но я подумал, что это может быть более понятным в качестве примера

class Resolver(threading.Thread):
    def __init__(self, addresses, result_dict):
        threading.Thread.__init__(self)
        self.addresses = addresses  # Now takes in a list of multiple addresses
        self.result_dict = result_dict

    def run(self):
        for address in self.addresses: # do your existing code for every address in the list
            try:
                content = urllib.urlopen("http://www.siteadvisor.com/sites/" + address).read(12000)
                search1 = content.find("didn't find any significant problems.")
                search2 = content.find('yellow')
                search3 = content.find('web reputation analysis found potential security')
                search4 = content.find("don't have the results yet.")

                if search1 != -1:
                    result = "safe"
                elif search2 != -1:
                    result = "caution"
                elif search3 != -1:
                    result = "warning"
                elif search4 != -1:
                    result = "unknown"
                else:
                    result = ""

                self.result_dict[address] = result
            except:
                pass
  • 0
    Можете ли вы опубликовать пример, пожалуйста?
  • 0
    Я только что отредактировал свой ответ на коротком примере - вам нужно будет отредактировать ваш метод run чтобы передавать списки адресов вместо одного адреса, но я оставил это вам, поскольку не знаю, как работает ваш входной файл и т. Д. отформатирован, и я не хочу передавать сломанный код. Как видите, это небольшое изменение.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню