2012-05-21 3 views
0

필자는 현재 나의 파이썬 기술이 충분하지 않은 지점에 작은 파이썬 응용 프로그램을 작성하고 다시 작성했습니다. Beautiful Soup을 파서로 사용하는 단일 스레드 응용 프로그램에서 시작하여 lxml로 변경되었습니다. 스크립트를 멀티 스레드로 만들었으므로 뒤틀린 것을 발견했지만이 작은 조각을 뒤틀 수는 없습니다. 나는 이것을 여기에 게시 할 것입니다. 아마 여러분들은 저에게 좀 더 빠른 방향을 제시 할 수있는 더 나은 방향을 가르쳐 줄 수있을 것입니다. 150k 페이지를 가져 오려면이 시점에서 1 시간이 필요합니다. Iam은이 문제에 만족했습니다. 처음 쓰려고했을 때 3 배 느려졌습니다.Datamining Multithreading vs Multiprocessing

#! /usr/bin/python 
# coding: ISO-8859-1 
import time, PySQLPool, Queue, threading 
from urllib3 import connection_from_url 
from lxml import etree 
import cStringIO as StringIO 

headers = { 
      'User-Agent'   : 'Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)', 
      'Accept'    : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 
      'Accept-Language' : 'en-us;q=0.5,en;q=0.3', 
      'Accept-Encoding' : 'gzip, deflate', 
      'Accept-Charset'  : 'utf-8;q=0.7,*;q=0.7' 
} 

t = time.time() 
PySQLPool.getNewPool().maxActiveConnections = 60 
db = PySQLPool.getNewConnection(username='user', password='pass', host='127.0.0.1', db='fddb') 
pool = connection_from_url('http://fddb.info/', maxsize=60, timeout=150, headers=headers) 
detailCounter = 0 
urls = {} 
queue = Queue.Queue() 
out_queue = Queue.Queue() 

clean_rows = { 
       "Brennwert":"details_brennwert", 
       "Kalorien":"details_kalorien", 
       "Protein":"details_protein", 
       "Kohlenhydrate":"details_kohlenhydrate", 
       "davon Zucker":"details_zucker", 
       "davon Polyole":"details_polyole", 
       "Fett":"details_fett", 
       "Ballaststoffe":"details_ballaststoffe", 
       "Broteinheiten":"details_broteinheit", 
       "Alkohol":"details_alkohol", 
       "Cholesterin":"details_cholesterin", 
       "Koffein":"details_koffein", 
       "Wassergehalt":"details_wasser", 
       "Vitamin C":"details_vitc", 
       "Vitamin A":"details_vita", 
       "Vitamin D":"details_vitd", 
       "Vitamin E":"details_vite", 
       "Vitamin B1":"details_vitb1", 
       "Vitamin B2":"details_vitb2", 
       "Vitamin B6":"details_vitb6", 
       "Vitamin B12":"details_vitb12", 
       "Natrium":"details_natrium", 
       "Eisen":"details_eisen", 
       "Zink":"details_zink", 
       "Magnesium":"details_magnesium", 
       "Chlor":"details_chlor", 
       "Mangan":"details_mangan", 
       "Schwefel":"details_schwefel", 
       "Kalium":"details_kalium", 
       "Kalzium":"details_kalzium", 
       "Phosphor":"details_phosphor", 
       "Kupfer":"details_kupfer", 
       "Fluor":"details_fluor" 
       } 

def rows_escape(text): 
    for item, key in clean_rows.items(): 
     text = text.replace(item, key) 
    text = text.rstrip() 
    return text 

clean_values = { 
     "kJ" :"", 
     "kcal" :"", 
     "g" :"", 
     "mg" :"", 
     "%" :"", 
     "," :".", 
     u"\u03bc": "" 
     } 

def values_escape(text): 
    for item, key in clean_values.items(): 
     text = text.replace(item, key) 
    text = text.rstrip() 
    return text 

def insertDetails(container, foods_id): 
    c = PySQLPool.getNewQuery(db) 
    query_rows = '' 
    query_values = '' 
    for item in container: 
     query_rows += item['row'] + ',' 
     query_values += item['value'] + ',' 

    c.Query("INSERT INTO details (%sdetails_id,foods_id) VALUES (%sNULL,%s)" % (query_rows, query_values, foods_id)) 
    c.Query("UPDATE foods SET foods_check = '1' WHERE foods_id=%d" % (foods_id)) 

def getHP(url): 
    r = pool.request('GET', '/' + url) 
    return r.data 

class ThreadUrl(threading.Thread): 
    def __init__(self, queue, out_queue): 
     threading.Thread.__init__(self) 
     self.queue = queue 
     self.out_queue = out_queue 
    def run(self): 
     while True: 
      host = self.queue.get() 
      data = getHP(host[0]) 
      self.out_queue.put([data, host[1]]) 
      self.queue.task_done() 

class DatamineThread(threading.Thread): 
    def __init__(self, out_queue): 
     threading.Thread.__init__(self) 
     self.out_queue = out_queue 
    def run(self): 
     while True: 
      global detailCounter 

      qData = self.out_queue.get() 
      data = qData[0] 
      foods_id = qData[1] 

      container = [] 
      parser = etree.HTMLParser(encoding='cp1252') 
      tree = etree.parse(StringIO.StringIO(data), parser) 
      divx = tree.xpath('//div[@style="background-color:#f0f5f9;padding:2px 4px;" or @style="padding:2px 4px;"]') 

      for xdiv in divx: 
       x = etree.ElementTree(element=xdiv, parser=parser) 

       value = x.xpath('string(//div/text())') 
       label = x.xpath('string(//*[self::a or self::span]/text())') 

       label = rows_escape(label) 

       if not "[nodata]" in value: 
        if u"\u03bc" in value: 
         value = values_escape(value) 
         item4 = 0 
         item4 = float(value) 
         item4 = item4/1000 
         container.append({'row':label,'value':str(item4)}) 
        else: 
         container.append({'row':label,'value':values_escape(value)}) 

      detailCounter += 1 
      container = tuple(container) 
      insertDetails(container, foods_id) 

      self.out_queue.task_done() 

def main(): 

    c = PySQLPool.getNewQuery(db) 
    c.Query("SELECT foods_id, foods_url FROM foods WHERE foods_check = 0") 
    urls = c.record 

    for i in range(6): 
     t = ThreadUrl(queue, out_queue) 
     t.setDaemon(True) 
     t.start() 

    for item in urls: 
     queue.put([item['foods_url'], item['foods_id']]) 

    for i in range(6): 
     dt = DatamineThread(out_queue) 
     dt.setDaemon(True) 
     dt.start() 

    queue.join() 
    out_queue.join() 

main() 
db.close 
print "Zeit: %.2f New Details: %d" % (time.time()-t, detailCounter) 
+0

응용 프로그램의 dbfetch/memory/cputime 프로파일 링을 수행하고 맹목적으로 최적화를 시도하기 전에 실제 병목 현상을 식별하십시오. – moooeeeep

답변

1

다중 CPU가 있고 프로그램의 CPU 사용량이 매우 많은 경우 다중 처리 모듈을 사용하는 것이 좋습니다. 파이썬은 글로벌 인터프리터 잠금 (Global Interpreter Lock) 또는 GIL을 통해 멀티 스레딩에서 악명이 높습니다. GIL은 기본적으로 주어진 시간에 단일 프로세스에서 파이썬 스레드 하나만 실행할 수 있도록합니다.

+0

글쎄, 멀티 프로세싱 및 트위스트. 그러나 어떻게 든 그들은 내가 거기에서 게시했던 나의 짤깍 소리가 났던 더 느린 것. – Cango

+0

아 아아 : bc URL 가져 오기 또는 cpu가 병목 현상이 될 것입니다. 루프에서 먼저 URL을 가져 와서 처리하는 프로세스의 코어 수를 2 * 또는 3 *으로 제안하십시오. 여분의 동기화가 반드시 당신을 죽일 것입니다. –