Cudatext: Expanding a folder in project_man slow

Created on 25 Jul 2021  ·  17Comments  ·  Source: Alexey-T/CudaText

Работаю с CMS Bitrix, в нем есть папка /bitrix/components/bitrix/, и в этой папке лежит около 400 папок, без файлов. Дома на компьютере с SSD раскрытие папки около 170-300 мс (измеряю время выполнения функции action_rerfresh()), чем больше файлов/папок тем медленнее. На работе компонентов больше, и диск медленнее, там это заметнее.

Попытался исправить сам. Первым делом вставил if i % 10 == 0: app_idle(), так интерфейс не замораживается, но время перед открытием папки увеличивается.

Потом добавил TREE_LOCK, по коду ниже это есть, задержка стала 90-190 мс, но все равно ощущается, в SublimeText ее нету, достичь бы такого же поведения...

# /py/cuda_project_man/__init__.py
# line: 492

    def action_refresh(self, parent=None):
        unfold = parent is None
        if parent is None:
            # clear tree
            tree_proc(self.tree, TREE_ITEM_DELETE, 0)

            if self.project_file_path is None:
                project_name = PROJECT_UNSAVED_NAME
            else:
                project_name = self.project_file_path.stem

            parent = tree_proc(
                self.tree,
                TREE_ITEM_ADD,
                0,
                -1,
                project_name,
                self.ICON_PROJ,
            )

            #select 1st node
            items_root = tree_proc(self.tree, TREE_ITEM_ENUM, 0)
            tree_proc(self.tree, TREE_ITEM_SELECT, items_root[0][0])

            nodes = self.project["nodes"]
            self.top_nodes = {}
        else:
            fn = self.get_location_by_index(parent)
            if not fn: return
            #print('Reading dir:', fn)
            try:
                nodes = sorted(Path(fn).iterdir(), key=Command.node_ordering)
            except:
                tree_proc(self.tree, TREE_ITEM_SET_ICON, parent, image_index=self.ICON_BAD)
                return
        new_nodes = []
        for path in map(Path, nodes):
            spath = str(path)
            sname = path.name
            if is_win_root(spath):
                sname = spath
            elif self.options.get("no_hidden", True) and is_hidden(spath):
                continue
            elif self.is_filename_ignored(spath):
                continue

            if is_locked(spath):
                imageindex = self.ICON_BAD
            elif path.is_dir():
                imageindex = self.ICON_DIR
            elif is_simple_listed(path.name, MASKS_IMAGES):
                imageindex = self.ICON_IMG
            elif is_simple_listed(path.name, MASKS_ZIP):
                imageindex = self.ICON_ZIP
            elif is_simple_listed(path.name, MASKS_BINARY):
                imageindex = self.ICON_BIN
            else:
                lexname = lexer_proc(LEXER_DETECT, path.name)
                if lexname:
                    imageindex = self.icon_get(lexname)
                else:
                    imageindex = self.ICON_ALL

            new_nodes.append({
                'sname': sname,
                'imageindex': imageindex,
                'spath': spath   
            })
###################################################            
        tree_proc(self.tree, TREE_LOCK)

        for new_node in new_nodes:
            index = tree_proc(
                self.tree,
                TREE_ITEM_ADD,
                parent,
                -1,
                new_node['sname'],
                new_node['imageindex'],
                data=new_node['spath'],   
            )

            if nodes is self.project['nodes']:
                self.top_nodes[index] = path

            # dummy nested node for folders
            if new_node['imageindex'] == self.ICON_DIR:
                tree_proc(
                    self.tree,
                    TREE_ITEM_ADD,
                    index,
                    -1,
                    'dummy',
                    -1
                )

        tree_proc(self.tree, TREE_UNLOCK)
###################################################

        if unfold:
            tree_proc(self.tree, TREE_ITEM_UNFOLD, parent)
plugins

Most helpful comment

Тормозят системные вызовы is_file и is_dir, не tree_proc.

Если возможно (не уверен) переделать это Path(fn).iterdir() на os.scandir - должно быть значительно быстрее. У меня Path.iterdir + is_dir на большой папке занимает 140 мс, а os.scandir + is_dir - 18 мс.

All 17 comments

Кажется мы уже упираемся в скорость АПИ (вряд ли скорость чтения папки питоном такая медленная). может можно было бы добавитть АПИ для "добавить много узлов сразу", не знаю.

Не пойму куда вы вставили LOCK/UNLOCK, можете дать весь файл или pullreq?

Не пойму куда вы вставили LOCK/UNLOCK, можете дать весь файл или pullreq?

image

Кажется мы уже упираемся в скорость АПИ (вряд ли скорость чтения папки питоном такая медленная). может можно было бы добавитть АПИ для "добавить много узлов сразу", не знаю.

Вроде бы по замерам основное время как раз на добавление элементов в дерево и уходит, попробую позже тогда сделать нативную функцию принимающую несколько элементов, если других вариантов пока не видно.

Добавил LOCK/UNLOCK - в новую обертку, т.к. добавление в action_refresh трудно, там внутри парочка return (они бы вышли без делания UNLOCK).

попробую позже тогда сделать нативную функцию принимающую несколько элементов, если других вариантов пока не видно.

я думал сделать передачу туда - это просто новый акшен TREE_ITEM_ADD_MANY- словарика. он бы держал в себе все детали про Н пунктов дерева.
Вопрос насколько это надо! у вас время около 200мс- надо ли ради того городить чтото?

У меня самую бОльшую часть времени занимают вызовы к is_file и is_dir, а заполнение дерева очень быстрое.

И еще при повторном открытии - удаление детей очень много времени занимает. Тут тоже нужен бы TREE_LOCK

Так нужно сначала точно знать что тормозит- чтение папки или АПИ tree_proc?

Тормозят системные вызовы is_file и is_dir, не tree_proc.

Если возможно (не уверен) переделать это Path(fn).iterdir() на os.scandir - должно быть значительно быстрее. У меня Path.iterdir + is_dir на большой папке занимает 140 мс, а os.scandir + is_dir - 18 мс.

А, ясно, значит надо переделать на scandir. patch welcome.

У меня самую бОльшую часть времени занимают вызовы к is_file и is_dir, а заполнение дерева очень быстрое.

У меня is_file, is_dir, итд где то 10-20% времени съедает от общего выполнения функции, Windows 10.

https://github.com/Alexey-T/CudaText/pull/3607

Создал 1600 папок, при открытии файловые операции начали действительно отъедать основное время.

Я потестил плагин со scandir(), вроде все окей, но возможно я что то сломал. В чем кстати суть двух одинаковых .py файлов в разных местах?

@memstream is_filename_ignored() проверяет os.path.isdir для каждого файла - у меня 25% времени где-то занимает (4000 папок)

двух одинаковых .py файлов в разных местах?

второе место исп-тся МакОС пакетом. его сборкой. генерировать автоматом- не поулчилось.

не закрываю, т.к. надо фиксить что @halfbrained выше сказал.

оптимизировал- тепеорь is_dir() не дергается лишние разы в is_filename_ignored(). проверьте плиз.

оптимизировал- тепеорь is_dir() не дергается лишние разы в is_filename_ignored(). проверьте плиз.

У меня функция action_refresh_int на тестовой папке отрабатывает 0.03с, хороший результат

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Alexey-T picture Alexey-T  ·  5Comments

rhinolophus picture rhinolophus  ·  5Comments

xcme picture xcme  ·  5Comments

JairoMartinezA picture JairoMartinezA  ·  7Comments

Alexey-T picture Alexey-T  ·  5Comments