Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 2, 2011 13:26:51

MichaelN
От:
Зарегистрирован: 2011-04-02
Сообщения: 23
Репутация: +  0  -
Профиль   Отправить e-mail  

На стандартном примере потоков не вижу performance

Привет, Всем.
Помогите разобраться.
Имеется 50 файлов по 100 000 тыс. записей
В них буду искать слова и подсчитывать из количество.

#!/usr/bin/env python
# coding=utf-8

import threading as t
import time, re
import Queue

def parseit( num ):
global total
log = open('log_%d' % num)
lines = log.readlines()

for line in lines:
if re.search('miki', line):
total += 1

class Parse( t.Thread ):
def __init__(self, work_queue):
self.work_queue = work_queue
t.Thread.__init__(self)

def run(self):
while True:
filename = self.work_queue.get()
self.process( filename )
self.work_queue.task_done()

def process(self,filename):
global total
log = open(filename)
lines = log.readlines()

for line in lines:
if re.search('miki', line):
total += 1


def test1():
global total
total = 0
for i in range(1,50):
parseit(i)
print total

def test2():
global total
THREAD = 3
total = 0
work_q = Queue.Queue()
lst_file = ['log_%d' % x for x in range(1,50) ]

for item in lst_file:
work_q.put( item )

for i in range( THREAD ):
tr = Parse(work_q)
tr.setDaemon(True)
tr.start()
work_q.join()
print total

start = time.time()
test1()
print 'Послед.: %f'.decode('utf-8') % (time.time() - start)
start = time.time()
test2()
print 'Потоки: %f'.decode('utf-8') % (time.time() - start)
Вот мой вывод:
Microsoft Windows
© Корпорация Майкрософт (Microsoft Corp.), 2009. Все права защищены.
E:\DevProject\etest>thtest.py
815220
Послед.: 12.529000
789345
Потоки: 18.775000

E:\DevProject\etest>thtest.py
815220
Послед.: 12.357000
789265
Потоки: 18.825000

E:\DevProject\etest>thtest.py
815220
Послед.: 12.237000
789370
Потоки: 20.780000
Объясните мне почему.



Офлайн

#2 Окт. 2, 2011 13:58:02

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

На стандартном примере потоков не вижу performance

1 Почитайте про GIL. Потоки в питоне выполняются одновременно, но не для питоновского кода. Используйте multiprocessing там кстати есть и map-reduse который можно тут использовать.

2 Читайте не по строкам, а все целиком
3 Регулярные выражения компилируйте и применяйте к длинной строке
4 в случае “miki” быстрее будет работать поиск подстроки.
5 Оно у вас неправильно работает если в строке несколько “miki” (или может быть правильно, тогда совет 2 не подойдет).



Офлайн

#3 Окт. 3, 2011 09:30:04

Isem
От:
Зарегистрирован: 2010-08-27
Сообщения: 447
Репутация: +  7  -
Профиль   Отправить e-mail  

На стандартном примере потоков не вижу performance

Последовательное чтение файлов выполняется заметно быстрее, чем постоянное перепрыгивание с одного на другой и обратно (перемещение магнитной головки диска с дорожки на дорожку требует кучу времени). Читайте файлы последовательно, а вот поиск делайте параллельно в разных нитках. Чтение файла сразу в нескольких нитках будет всегда медленнее, чем чтение того же файла в одной нитке. Головка то одна.



Офлайн

#4 Окт. 12, 2011 16:31:22

MichaelN
От:
Зарегистрирован: 2011-04-02
Сообщения: 23
Репутация: +  0  -
Профиль   Отправить e-mail  

На стандартном примере потоков не вижу performance

Этот пример я не из головы выдумал он был дан в качестве пример в журнале LINUX-FORMAT
Вот ссылка http://wiki.linuxformat.ru/index.php/LXF82:Python
Вот название пример THREAD-TEST.PY
Хороший пример с я нашел в книги Python в системном администрировании UNIX и Linux.
Может кому пригодится.
Опрос сети.

#!/usr/bin/python
# -*- coding: utf-8 -*-

#

from threading import Thread
import subprocess
from Queue import Queue
import time

num_threads = 5
queue1 = Queue()
queue2 = Queue()
ips = [ '192.168.1.%d' %x for x in range( 20 ) ]

def pinger(i, q):
#опрос подсети
while True:
ip = q.get()
print "Thread %s: Pinging %s" % (i, ip)
ret = subprocess.call('ping -n 1 %s' % ip, shell=True, stdout=False)
if ret == 0:
print "%s: is alive\n" % ip
else:
print "%s: did not respond\n" % ip
q.task_done()

def test1():
for ip in ips:
queue1.put(ip)

for i in range(num_threads):
worker = Thread(target=pinger, args=(i, queue1))
worker.setDaemon(True)
worker.start()

print "Main Thread Waiting'"
queue1.join()

def test2():
start = time.time()
for ip in ips:
queue2.put(ip)

for x in range(10):
ipp = queue2.get()
print 'ping: %s' % ipp
p = subprocess.call('ping -n 1 %s' % ipp, shell=True, stdout=False)
queue2.task_done()

start1 = time.time()
test1()
print 'Task1: {0}'.format( time.time() - start1 )

start2 = time.time()
test2()
print 'Task2: {0}'.format( time.time() - start2 )



Офлайн

#5 Окт. 20, 2011 11:24:26

Chrizt
От: Владивосток
Зарегистрирован: 2009-07-18
Сообщения: 88
Репутация: +  0  -
Профиль   Отправить e-mail  

На стандартном примере потоков не вижу performance

MichaelN,
А Вы в курсе, что Ваши принты тоже неслабо задерживают программу =)
Особенно это заметно в IDLE в шелле.

doza_and
Потоки в питоне выполняются одновременно, но не для питоновского кода.
А вот это я вообще не понял. Как-то взорвало мозг.
Про GIL я в курсе, читал, но Ваше предложение вообще не сдюжил :(



Офлайн

#6 Окт. 20, 2011 20:54:09

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

На стандартном примере потоков не вижу performance

:) Извините пробовал коротко выразиться
см например http://habrahabr.ru/blogs/python/84629/

Потоки в питоне выполняются одновременно <=> “Python threads — это настоящие потоки (POSIX threads или Windows threads), полностью контролируемые ОС.”

но не для питоновского кода <=> “В этом вся загвоздка: в любой момент может выполняться только один поток Python. Глобальная блокировка интерпретатора — GIL — тщательно контролирует выполнение тредов.”



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version