Python и SEO

Архив ‘queue’ тега

Multiprocessing

комментарии: 8

Узнал про модуль spynner, это такой управляемый браузер. Если на страничке много трудноподдающегося JavaScript-а, то вместо urllib2 или curl можно попробовать натравить на него spynner. Основы работы с ним можно почитать здесь. В общем был он нужен мне, но проблема в том, что он достаточно медленный, а работать в несколько потоков с ним не представляется возможным, так он берет своё начало от GUI-класса библиотеки Qt, которые в свою очередь можно использовать только в main-потоке. Поэтому вместо многопоточности пришлось думать о многопроцессовости. Ну это тоже самое если сделать однопоточный скрипт и
запустить одновременно N его копий. Про многопоточность я уже написал один пост, который полностью состоит из быдлокода=) С тех пор, я чутка поумнел и для организации потоков наследуюсь от класса Thread. С многопроцессовостью всё аналогично, только классы другие, а методы и структура вся та же.

# coding: utf8
import spynner
from spynner import browser
import multiprocessing
from multiprocessing import Process

class Serfer(multiprocessing.Process):
    def __init__(self,queue):
        multiprocessing.Process.__init__(self)
        self.__queue = queue # наша очередь заданий
        self.kill_received = False # На всякий случай переменная, вдруг надо будет всё остановить
    def run(self):
        while not self.kill_received:
            try: item = self.__queue.get_nowait() # ждём данные
            except Queue.Empty: break

            error = True
            try: error = self.serfing(item)
            except: traceback.print_exc()

            time.sleep(0.1)
            self.__queue.task_done() # задача завершена
            if error: self.__queue.put(item) # Если была ошибка, то еще раз с этими данными
        return
    def serfing(self,url):

        br = browser.Browser() # запускаем браузер
        br.create_webview()
        br.show() # отображаем
        br.load(url) # загружаем страницу
        br.wait_a_little(75)

        br.destroy_webview()
        br.close() # закрываем браузер

def main():
    queue = multiprocessing.JoinableQueue() # создаем очередь заданий
    processes = 5
    # Урлы по которым надо будет перейти в браузере
    urls = ["http://ya.ru","http://google.ru","http://yahoo.com",
"http://bing.com","http://rambler.ru"]

    for url in urls:
        queue.put(url) # заносим данные в очередь
    for i in xrange(processes):
        t = Serfer(queue) # создаем процесс
        t.start() # стартуем
        time.sleep(0.1)
    queue.join() # приостанавливаем дальнейшее выполнение кода, пока очередь не опустошится
    print "Done"
if __name__ == '__main__':
    main()

Автор: kalombo

Сентябрь 29th, 2011 at 10:56 пп

Категория: GUI,Python

Tagged with , , ,

Пул потоков. Модуль Threading.

комментарии: 9

Я думаю,  пример из SEO-софта на тему пула потоков долго искать не придется. Взять тот же Хрумер. Указал количество потоков, например 20, запустил – все 20 работают, как только один из них завершит работу – запускается следующий и так, пока не закончатся ссылки. Наверное в 9 из 10 случаев я пишу скрипт с использованием пула потоков.  Рассмотрим некторые примеры.

Пример 1. «В лоб».

    threads = []
    for x in range(THREADS):
        new_thread = threading.Thread(target=step_one)
        threads.append(new_thread)
        new_thread.start()
        time.sleep(1)
    while True: # какое-то условие
        for y in threads[:]:
            if not y.isAlive():
                threads.remove(y)
                new_thread = threading.Thread(target=step_one)
                threads.append(new_thread)
                new_thread.start()
        time.sleep(0.1)
    while threading.activeCount()>0:
        time.sleep(5)

Функцию step_one запускаем в несколько потоков, все созданные потоки храним в списке. Затем провереяем в цикле какие потоки завершили работу и, если такие есть, создаем новые и так, пока не достигнем какого-либо результата. Криво, неудобно, зато сразу понятно. Достаточно долго пользовался такой реализацией, а всё из-за лени.

Пример 2. Семафоры.

import time
import threading
max_potokov = 20
maxconnections = 5
akkiQueue = threading.BoundedSemaphore(value=maxconnections)

def doform():
    akkiQueue.acquire()
    # код функции
    akkiQueue.release()

for i in xrange(max_potokov):
    time.sleep(1)
    p = threading.Thread(target=doform)
    p.setDaemon(True)
    p.start()
while threading.activeCount()>0:
    time.sleep(5)

Уже лучше, количество потоков контролируется, но надо заранее знать сколько будет потоков, в общем как-то изворачиваться если тебе надо будет прервать все эти потоки по условию.

Пример 3. Очереди.

queue = Queue.Queue() # создаем очередь

def register(item):
    #Функция с основным кодом
    return
def repeat():
    while True:
        try:
            item = queue.get_nowait() # ждём данные
        except Queue.Empty:
            break
        register(item) # передаем данные в нашу функцию
        time.sleep(0.5)
        queue.task_done() # задача завершена
for item in range(MAX_THREADS):
    queue.put(item) # заносим данные в очередь
for i in xrange(THREADS):
    t = threading.Thread(target=repeat) # создаем нить
    t.start() # стартуем
    time.sleep(0.5)
queue.join() # блокируем очередь до завершения

Здесь используется модуль Queue. На данный для меня самый удобный варинат – и выглядит красиво, и данные передавать можно.

Помимо тех вариантов, что я описал, можно погуглить на тему threadpool и найти какие-нибудь модули для организации пула потоков.

Автор: kalombo

Октябрь 6th, 2009 at 9:32 пп

Категория: Python

Tagged with , threading, питон, семафор