Уведомления

Группа в Telegram: @pythonsu

#1 Фев. 11, 2014 14:15:46

Ace
Зарегистрирован: 2012-09-05
Сообщения: 43
Репутация: +  0  -
Профиль   Отправить e-mail  

Excel - работа с одним файлом в несколько потоков

Добрый !

Задача: в файле экселя набиты запросы к БД. Запросы идут к нескольким (>100) серверам одновременно. Время ответа от серверов разное.

Что пытаюсь: открыть 1 раз файл экселя, запустить потоки для чтения и выполнения запросов по каждому серверу (1 поток = 1 сервер, при выполнении не ждет соседа)

Вопросы:
- как использовать единственный экземпляр источника запросов ?
- использует ли эксель какой-то курсор внутри себя для доступа к данным ячеек ? Можно ли использовать несколько потоков для доступа в разные места одного файла экселя ?
- или технология в принципе неудачная ?

# coding: cp1251
from win32com.client import Dispatch
import cx_Oracle
import pythoncom
import fdb
import datetime
import sys
import threading
import pprint
import time
data_n="'01.01.2014'"
data_y="'01.01.2013'"    
res_spaces_queue=[]
ora_mutex=threading.Lock()
def xls(id,target_host,Sheet,x,y,sql):    
    try:
        pythoncom.CoInitialize()
        # подключаемся к целевому серверу с данными и получаем сами данные
        ora_con = cx_Oracle.connect("orauser/orapass@"+target_host+"/XE",threaded=True)
        ora_cur = ora_con.cursor()            
        ora_cur.execute(r"alter session set NLS_DATE_FORMAT = 'DD.MM.YYYY'")        
        ora_cur.execute(sql)
        for result in ora_cur:
            ora_mutex.acquire()            
            # записываем результат в запасник
            res_spaces_queue.append([id,result[0],str(start_time),str(datetime.datetime.now()-start_time)])
            ora_mutex.release()            
            
        ora_cur.close()
        ora_con.close()
    except Exception as e1:
        print(str(id)+" fun error:","Line "+format(sys.exc_info()[-1].tb_lineno),e1.__str__())
    finally:        
        pythoncom.CoUninitialize()
#==================================================================      
def main(argv=None):
    # получаем из посторонней БД данные по параметрам подключения к серверам данных. так получается :)
    fb_conn = fdb.connect(dsn='firebird:d:\\NET_ANALISYS.FDB',user='fbuser',password='fbpass')
    fb_cur = fb_conn.cursor()
  
    SELECT=r"SELECT p.gissz_num,p.lanaddress FROM points p"
    fb_cur.execute(SELECT)
    # открываем сам эксель-файл
    xlApp = Dispatch("Excel.Application")
    xlApp.Visible=True
    xlWb = xlApp.Workbooks.Open(r"d:\documents\sql.xlsx")    
    try:
        # пробегаем по списку серверов из БД
        for row in fb_cur.fetchall():
            # перебираем листы в excel
            for Sheet in xlWb.WorkSheets:
                # перебираем столбцы в листе excel
                for y in range(8,12):
                    # перебираем строки в листе excel
                    for x in range(4,12):
                        # мелкий анализ и исправление данных в целевой ячейке
                        sql=Sheet.Cells(y,x).Formula.upper().strip()
                        sql=sql.replace(":DATA_N",data_n)
                        sql=sql.replace(":DATA_Y",data_y)
                        if sql.find('SELECT ')==0:
                           # перебираем столбцы в листе excel
                            t = threading.Thread(target=xls,name='id'+str(row[0]),args=(row[0],row[1],Sheet.Name,x,y,sql))         
                            t.start()
        
        while threading.activeCount()>1:
            if threading.activeCount()<2:
                print(datetime.datetime.now(),threading.enumerate(),"\n------------",)
            time.sleep(3)
    except Exception as e3:        
        print("main try:","Line "+format(sys.exc_info()[-1].tb_lineno),e3.__str__())
    xlApp.Quit()
#==========================================        
if __name__ == "__main__":
    main()
Возможно, вопрос не к питону, а к экселю.

Офлайн

#2 Фев. 11, 2014 15:05:13

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

Excel - работа с одним файлом в несколько потоков

Ace
- или технология в принципе неудачная ?
Скорее да, неудачная. Надо считать все запросы в память. И потом уж запускать кучу потоков. Набивать запросы в Экселе вообще странная идея. По моему мнению лучше в текстовом файле по запросу на строчку набить. Так и генерировать их проще и регулярными выражениями обрабатывать. Но вам конечно виднее. Эксель по моему мнению это GUI к таблицам, если таблиц нет то и эксель в топку.



Офлайн

#3 Фев. 11, 2014 15:14:02

Ace
Зарегистрирован: 2012-09-05
Сообщения: 43
Репутация: +  0  -
Профиль   Отправить e-mail  

Excel - работа с одним файлом в несколько потоков

ИМХО в этой ситуации чтение в память тоже вариант не очень. Реально 157 целевых серверов, запросов примерно примерно 800, причем текст длинный. Большой расход ОЗУ.

Как можно использовать 1 объект эксель-апп , только глобалвар или можно передать как-то указатель эксель-апп в функцию потока ?

Офлайн

#4 Фев. 12, 2014 04:40:59

pyuser
От:
Зарегистрирован: 2007-05-13
Сообщения: 658
Репутация: +  36  -
Профиль   Отправить e-mail  

Excel - работа с одним файлом в несколько потоков

По вопросу использования одного COM-объекта в разных потоках смотрите функции:

CoMarshalInterThreadInterfaceInStream
CoGetInterfaceAndReleaseStream



Офлайн

#5 Фев. 12, 2014 05:38:24

PooH
От:
Зарегистрирован: 2006-12-05
Сообщения: 1948
Репутация: +  72  -
Профиль   Отправить e-mail  

Excel - работа с одним файлом в несколько потоков

Ace
ИМХО в этой ситуации чтение в память тоже вариант не очень. Реально 157 целевых серверов, запросов примерно примерно 800, причем текст длинный. Большой расход ОЗУ.
Т.е. чисто текст в память много, а а текст + вся немалая экселевская инфраструктура - нормально?! :)

Опять же, что значит много? Пусть 200 серверов, пусть по 1000 запросов, пусть запросы по килобайту(больше десяти строк по 80 символов, куда же больше?) получаем ~200 мегабайт, у меня одна вкладка Chrom`a жрет больше.

Опять же зачем все сразу в память читать? Организуем пул потоков, штук 20, очередь задач, один поток читает построчно файла(ну пусть даже и экселевский) и ставит задачи в очередь (не все сразу, а так чтобы в очереди не больше, скажем, 30 штук было). Потоки из пула читают задачи из очереди и выполняют. Основной поток следит за наполнением очереди и подкидывает, как весь файл пройден и очередь опустела - закончили.



Вот здесь один из первых отарков съел лаборанта. Это был такой умный отарк, что понимал даже теорию относительности. Он разговаривал с лаборантом, а потом бросился на него и загрыз…

Офлайн

#6 Фев. 12, 2014 11:25:32

Ace
Зарегистрирован: 2012-09-05
Сообщения: 43
Репутация: +  0  -
Профиль   Отправить e-mail  

Excel - работа с одним файлом в несколько потоков

2 PooH

Я понимаю, что ситуация изначально ненормальная - странные и разнообразные источники данных, уродливая структура. Увы, это изменить не в силах.

Использование пула потоков кончено имеет место, но эффект конечно будет не тот. КПД вырастет относительно чисто последовательного опроса, но на фоне нормального многопоточного опроса по каждому серверу независимо - не смотрится ВААЩЕ

——————————-

пошел изучать подсказку pyuser

——————————-
Изначально задуманный вариант:
1) создание 1го объекта ексель-апп
2) открытие в нем 1го исходного файла с запросами
3) создать потоки для каждого сервера, которые каждый по-своему со своей скоростью переберет и выполнит запросы на своем целевом сервере.
Тогда не нужен пул и скорость выполнения всей затеи = скорости выполнения всех запросов на самом медленном сервере

Офлайн

#7 Фев. 12, 2014 12:06:15

PooH
От:
Зарегистрирован: 2006-12-05
Сообщения: 1948
Репутация: +  72  -
Профиль   Отправить e-mail  

Excel - работа с одним файлом в несколько потоков

Вдогонку, данные из екселевского файла можно и без екселя считать http://www.python-excel.org/ и не будет проблем с COM в потоках.



Вот здесь один из первых отарков съел лаборанта. Это был такой умный отарк, что понимал даже теорию относительности. Он разговаривал с лаборантом, а потом бросился на него и загрыз…

Офлайн

#8 Фев. 12, 2014 12:30:15

Ace
Зарегистрирован: 2012-09-05
Сообщения: 43
Репутация: +  0  -
Профиль   Отправить e-mail  

Excel - работа с одним файлом в несколько потоков

спс, посмотрю технологию без СОМ

фактическая математика такая: 150 узлов, 1132 запроса, суммарный размер строк запросов для одного сервера 1 426 209 байт (измерялось getsizeof()) , итого всего 150*1436209~204 мб. Размер не гигантский, но тоже извращение …

сделаю решение целиком - опубликую

Отредактировано Ace (Фев. 12, 2014 12:32:53)

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version