Форум сайта python.su
Вот код, который был у меня на python. Это финальная версия, которая у меня получилась на python. Она съедает около 450 метров памяти. 10 гб у меня выжирала, какая-то из промежуточных реализаций (я баловалась с процессами, потоками и т д). Я переписывала раза 4 код.
izekia я даже не думала кидать камни в сторону python. Это один из моих любимых языков, просто столкнулась с ситуацией, когда выгодней и проще использовать другой язык, где без использования сторонних библиотек и в лоб задача решается оптимально по скорости и потребляемым ресурсам. Все таки для каждой задачи свой инструмент.
import math import queue import threading import terminaltables import numpy as np from config import ConfigParser def calc_entropy(alphabet: dict): return sum([-p * math.log(p, 2) for p in alphabet.values()]) def calc_parts(str_len: int, parts: int): """ Считает какой длинны генерировать строку каждому из процессов :param str_len: общая длинна строки """ parts = [str_len // parts] * parts diff = str_len - sum(parts) if diff != 0: parts[-1] += diff return parts def generate_part_text(alphabet, length, res_str, res_frequency): """ Генерирует строку с заданной вероястностью появления символов и считает сколько раз каждый из символов встречается в строке :param alphabet: :param length: длинна строки, которую надо сгенерировать :param res_str: очередь в которую помещается массив сгенеровынных символов :param res_frequency: очередь в котрую помещается словарь со списком символов и частотой его встречаемости """ part = np.random.choice( list(alphabet.keys()), p=list(alphabet.values()), size=length ) res_str.put_nowait(part) res_frequency.put_nowait(dict(zip(*np.unique(part, return_counts=True)))) def generate_text(alphabet: dict, length: int): result_str = queue.Queue() result_frequency = queue.Queue() count_thread = 6 if length < 10000000: count_thread = 1 generate_part_text(alphabet, length, result_str, result_frequency) else: all_tasks = [] for i in calc_parts(length, count_thread): thread = threading.Thread( target=generate_part_text, args=(alphabet, i, result_str, result_frequency) ) thread.start() all_tasks.append(thread) for i in all_tasks: i.join() # Объединятся результаты расчитанные в потоках text = np.array([], dtype='<U1') frequency = {} for i in range(count_thread): text = np.append(text, result_str.get_nowait()) for key, value in result_frequency.get_nowait().items(): frequency[key] = frequency.setdefault(key, 0) + value return text, frequency conf = ConfigParser() text, frequency = generate_text(conf.alphabet, conf.length) with open('out.txt', 'w') as out: out.write(text.view('U{}'.format(conf.length))[0]) data_table = [['Символ', 'Количество выпадений']] data_table.extend(frequency.items()) table = terminaltables.AsciiTable(data_table) print(table.table) print('Общая длинна строки: {}\nЭнтропия: {}'.format( conf.length, calc_entropy(conf.alphabet)) )
import os import configparser from collections import OrderedDict BASE_DIR = os.path.abspath(os.path.dirname(__file__)) class ConfigParser: def __init__(self): self._config = configparser.ConfigParser() self.length = 0 self.alphabet = OrderedDict() self.read() def read(self): self.alphabet.clear() self._config.read(os.path.join(BASE_DIR, 'config.conf')) for section in self._config.sections(): for i in self._config[section]['alphabet'].split(', '): i = i.split(':') self.alphabet[i[0]] = float(i[1]) if sum([i for i in self.alphabet.values()]) != 1.0: print('Сумма вероятностей должна быть равна 1.0') exit() self.length = int(self._config[section]['length'])
[general]
alphabet = a:0.1, b:0.3, c:0.6
length = 100000000
Офлайн
marina932ага, 450 похоже) 400 - это массив и там остальное питон.
Вот код, который был у меня на python. Это финальная версия, которая у меня получилась на python. Она съедает около 450 метров памяти. 10 гб у меня выжирала, какая-то из промежуточных реализаций (я баловалась с процессами, потоками и т д). Я переписывала раза 4 код.
Офлайн
Лучше не тратьте время на это, потому что я проблему свою уже решила и проблема закрыта и не актуальна. Что-то писать сейчас это просто тратить время.
izekiaРечь идет про расширения на си или cython?
я могу опуститься на, практически, самый низкий уровень, и на том же питоне с небольшими дополнениями, реализовать узкое место
Отредактировано marina932 (Ноя. 10, 2016 13:52:25)
Офлайн
marina932cython, конечно
Речь идет про расширения на си или cython?
marina932я не трачу время, это пишется быстро, мне самому интересно до какой степени это все можно оптимизировать
Лучше не тратьте время на это, потому что я проблему свою уже решила и проблема закрыта и не актуальна. Что-то писать сейчас это просто тратить время.
Отредактировано izekia (Ноя. 10, 2016 16:29:19)
Офлайн
izekiaЭто вообще ни как нельзя назвать “могу спуститься к более низкому уровню абстракций”, это написание расширения на компилируемом языке (с помощью довольно удобного инструмента конечно), но это уже не python. По сути писать расширения на си, можно к любым языкам и расширение на си сложно назвать кодом python.
cython, конечно
Офлайн
marina932cython - это надмножество языка python.
это написание расширения на компилируемом языке (с помощью довольно удобного инструмента конечно), но это уже не python
def sumpy(n): res = 0 for a in range(1, n + 1): res += a return res
%timeit sumpy(1000000)
%%cython def sumpy1(n): res = 0 for a in range(1, n + 1): res += a return res
%timeit sumpy1(1000000)
%%cython cpdef int sumcy(int n): cdef int a, res = 0 for a in range(1, n + 1): res += a return res
%timeit sumcy(1000000)
Отредактировано izekia (Ноя. 10, 2016 18:42:56)
Офлайн
всегда можно посмотреть во что транслируется код (я изменил определение функции, чтобы не было лишнего кода связанного с питоном)
+2: cdef int sumcy(int n): static int __pyx_f_46_cython_magic_3d048ac8c5c96bfcdd601bb78e692920_sumcy(int __pyx_v_n) { int __pyx_v_a; int __pyx_v_res; int __pyx_r; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("sumcy", 0); /* … */ /* function exit code */ __pyx_L0:; __Pyx_RefNannyFinishContext(); return __pyx_r; } +3: cdef int a, res = 0 __pyx_v_res = 0; +4: for a in range(1, n + 1): __pyx_t_1 = (__pyx_v_n + 1); for (__pyx_t_2 = 1; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) { __pyx_v_a = __pyx_t_2; +5: res += a __pyx_v_res = (__pyx_v_res + __pyx_v_a); } +6: return res __pyx_r = __pyx_v_res; goto __pyx_L0;
Отредактировано izekia (Ноя. 10, 2016 18:51:44)
Офлайн
Я прекрасно знаю, что такое cython. Моем мнение не изменилось. В общем свое мнение я высказала, переубеждать не собираюсь, у меня есть дела кроме этого.
Офлайн
marina932Да вас и не пытаются убедить, потому что непонятно в чем заключается ваше мнение, вы его невнятно высказали. Вы утверждали что питон потребляет в 100 раз больше памяти. Вам указали на очевидные ошибки при измерении и для питона и для Go. Вы жаловались что питон медленно выполняет код. Да это так.
Моем мнение не изменилось. В общем свое мнение я высказала,
marina932Не обижайтесь, я наверное более опытный программист и позволю себе высказать совет (вы сами утверждали что в GO вы только начинаете писать). Похоже что у вас много дел потому что вы пишете очень неэффективные программы и очень многословно, что на GO что на питоне.
у меня есть дела кроме этого.
Отредактировано doza_and (Ноя. 11, 2016 07:02:25)
Офлайн