LINUX.ORG.RU

[C/C++]Обход директории. Многопоточность.


0

2

Парни я вот чо-то не могу въехать. Мне например нужно находясь в текущей папки пройтись по ней и по всем дочерним папкам, использую несколько потоков. Как?! У меня пока ничего хорошего не получилось. Кто, что, может посоветует?!

man Рекурсия

Led ★★★☆☆
()

(=

Это основное тестовое задание для младшего разработчика компании eSignal =)

Написать нужно либо в MFC, либо в Qt ( но так-как HR-менеджер указывает на портируемость, то писать приходится на Qt =) ).

=)

Вспомнилось просто =)

m4n71k0r
()

у меня пока ничего хорошего не получилось.

не важно хорошо или не хорошо, расскажите каким путем вы пошли

anonymous2 ★★★★★
()
Ответ на: комментарий от rival

Если память не изменяет, то нужно было написать, чтобы программа не подавала признаков зависания при выборе директории и отображении её содержимого (поддиректорий и файлов), также необходимо было выводить статистику по расширениям файлов (всем файлам и в частности по файлам в текущей директории без учёта вложенных директорий). И всё это должно быть реализовано минимумом кода с максимумом «платформонезависимости».

Как-то так. Прямого ограничения на использование возможностей Qt не было.

m4n71k0r
()
Ответ на: (= от m4n71k0r

Так это, создаешь на основе QThread поток, который обходит директории и выдаёт промежуточные результаты через сигналы в гуй, не?

Kosyak ★★★★
()
Ответ на: комментарий от Kosyak

А без потока? А то повадились, чуть что, сразу поток.

baverman ★★★
()
Ответ на: комментарий от Legioner

Действительно, какой смысл? Упирается в IO. Я бы сделал обход и получение файлов однопоточным, а саму обработку, только если она того стоит, можно сделать многопоточной. Например, через акторы, посылая им задания асинхронно. Такое поведение при желании можно имитировать доступными средствами на более простых языках.

dave ★★★★★
()

Если это для продакшана, а не какое-нибудь учебное задание, то используйте лучше fts_open и не парьтесь.

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

hydraulicbrakefluid
()
Ответ на: комментарий от hydraulicbrakefluid

>глубокой (тысячи вложенных каталогов),

ИМХО тысячные уровни вложенности загнут любого. А кто-нибудь видел такую ситуацию. Не, я понимаю есть тысячи объектов в директории, но чтобы тысячи уровней вложенности.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

> ИМХО тысячные уровни вложенности загнут любого. А кто-нибудь видел такую ситуацию. Не, я понимаю есть тысячи объектов в директории, но чтобы тысячи уровней вложенности.

Не загнут, если через продолжения писать. Заменить обычную рекурсию на хвостовую. В F# для этого достаточно просто весь код обернуть в монаду Async и, вуаля, будет готово. Но задача, да, выдуманная :)

dave ★★★★★
()
Ответ на: комментарий от dave

Да, вообще, можно и без акторов обойтись. Есть простая очередь заданий, защищенная блокировкой. Есть пул исполняющих потоков. Пришло новое задание - ставим в очередь и будим потоки. Один из потоков забирает задание и исполняет. Все просто.

dave ★★★★★
()
Ответ на: комментарий от baverman

Нет, конечно. Только монада Async - это самое простое в использовании из того, что мне известно. Там пишется как бы «обычный» код и оборачивается в тег «async { ... }». Затем компилятором такой код автоматически разворачивается в хвостовую рекурсию. Минимум ручной работы :)

dave ★★★★★
()
Ответ на: комментарий от dave

Но ведь не каждый алгоритм итеративен, async же должен накладывать какие-то ограничения, чтоб гарантировать TCO. И я сейчас плохо соображаю, по-моему обход дерева каталогов так просто не развернешь.

baverman ★★★
()
Ответ на: комментарий от baverman

>по-моему обход дерева каталогов так просто не развернешь.

Я тоже так считаю. Как минимум одну «переменную»/«уровень вложенности» надо иметь. Другое дело, если итеративный процесс будет более экономично расходовать память. Это возможно, но принципиально проблему сверхвысокого уровня вложенности решить не удастся.

pathfinder ★★★★
()

нужно каждую папку сканировать отдельным потоком или просто сканирование сделать в потоке отличном от потока в котором крутится GUI messages?

ACR
()
Ответ на: комментарий от pathfinder

Под принципиальным решением я понимаю константное количество памяти на обход дерева любой глубины.

pathfinder ★★★★
()
Ответ на: комментарий от ACR

>нужно каждую папку сканировать отдельным потоком

А если этих папок ОЧЕНЬ много, то понадобится ОЧЕНЬ много потоков.

pathfinder ★★★★
()
Ответ на: комментарий от ACR

>или просто сканирование сделать в потоке отличном от потока в котором крутится GUI messages?

А вот это уже здравая мысль. Я думаю таким решением можно и ограничиться.

pathfinder ★★★★
()
Ответ на: комментарий от baverman

Разворачивается. Async не накладывает ограничений. Просто нужно обернуть вычисление в монаду. Тогда все while/for/try преобразуются в функциональную форму с гарантированным TCO. Это же касается рекурсивных вызовов, которые теперь превращаются в применение монадического bind - для него TCO тоже гарантировано. Тем более, что while строится через bind, а for - через while и try.

Это в ответ на ложное на мой взгляд утверждение, что «тысячные уровни вложенности загнут любого». Привел пример, где это не так.

dave ★★★★★
()
Ответ на: комментарий от Bad_Habit

> На Qt такая задачка решается даже без фантазии.

ага, щаззз, на Qt такая задачка решается далеко не оптимальным образом

QDirIterator напрямую не дает информацию, на каталог он указывает или на файл, в результате, так как ТС нужен многопоточный обход, ему потребуется дополнительный вызов stat (например через QFileInfo) на каждый пункт каталога, а это может очень-очень сильно сказаться на скорости

dt1 ★★
()
Ответ на: комментарий от pathfinder

> А если этих папок ОЧЕНЬ много, то понадобится ОЧЕНЬ много потоков

ОЧЕНЬ много потоков для современных систем не экзотика.

ACR
()

Вместо рекурсии моделируешь стек на куче, ну и потом уже разбиваешь проход по каждой ноде из корневой директории на свой поток, например.

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Гм. Хотя рекурсивные вызовы для прохода по каждой ноде из корневой директории тоже можно написать..

yoghurt ★★★★★
()
Ответ на: комментарий от ACR

8 мб на стек для потока по умолчанию в современной системе линукс

dt1 ★★
()
Ответ на: комментарий от dt1

> QDirIterator напрямую не дает информацию, на каталог он указывает или на файл, в результате, так как ТС нужен многопоточный обход, ему потребуется дополнительный вызов stat (например через QFileInfo) на каждый пункт каталога, а это может очень-очень сильно сказаться на скорости

Есть QDir::entryInfoList()

Bad_Habit
()
Ответ на: комментарий от hydraulicbrakefluid

>файловая система будет оооочень глубокой (тысячи вложенных каталогов)

В природе существует ограничение на максимальную длину пути, если ты не знал. Называется PATH_MAX и срезает «тысячи вложенных каталогов» буквально до пары тысяч при условии, что название каждогокаталога состоит из одного символа.

linuxfan
()
Ответ на: комментарий от Bad_Habit

> Есть QDir::entryInfoList()

не, это просто издевательство какое-то

что, по-твоему, возвращает QDir::entryInfoList()?

dt1 ★★
()
Ответ на: комментарий от Bad_Habit

QDir использует его на внутреннем уровне. Ну и как я написал уже, вызов QFileInfo - это неминуемые тормоза.

Сейчас посмотрел исходный код QDirIterator, он сам QFileInfo использует для всего подряд, это просто жесть какая-то.

В общем, самый быстрый способ чтения каталога - это readdir.

dt1 ★★
()
Ответ на: комментарий от dave

>Это в ответ на ложное на мой взгляд утверждение, что «тысячные уровни вложенности загнут любого»

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

Может популярно объяснишь, за счет чего можно достичь константного потребления памяти при обходе неупорядоченного дерева директорий произвольного размера?

pathfinder ★★★★
()
Ответ на: комментарий от dt1

> QDir использует его на внутреннем уровне.

Вот лажа, сам ни за что б не подумал. Qt провоцирует лень заглядывания в собственные сорцы..

В общем, самый быстрый способ чтения каталога - это readdir.

Ну так POSIX вообще лучший :)

Bad_Habit
()
Ответ на: комментарий от Legioner

просто рекурсивный обход есть, но хотелось бы использовать скажем 3-4 потока, но вот как сделать сихронизация между ними не пойму :(

Boy_from_Jungle ★★★★
() автор топика
Ответ на: комментарий от Boy_from_Jungle

>просто рекурсивный обход есть, но хотелось бы использовать скажем 3-4 потока, но вот как сделать сихронизация между ними не пойму :(

А нельзя ли сделать что-то вроде Jobs и пару рабочих тредов. Каждый Job сканирует дерево до определенной глубины и, если не если не дошел до конца, то добавляет новые задания в очередь. Правда тут надо продумать детали. Очень легко вывалится в огромное количество заданий в очереди. Можно в задании указывать: сканировать элементы в данной директории «от сих до сих» и соответственно каждая директория может породить не более X заданий, вне зависимости от числа элементов в ней. Как-то так.

pathfinder ★★★★
()
Ответ на: комментарий от Boy_from_Jungle

Ну и вообще тут говорили, что производительность упрется не в процессор а в дисковую подсистему.

pathfinder ★★★★
()
Ответ на: комментарий от placement_new

а gcc ее кстати же поддерживает? хвостовую то.

Хвостовую - да, упрощает.

quasimoto ★★★★
()
Ответ на: комментарий от pathfinder

fts_open - прекрасно справляется. Как-то приходилось писать AV-сканнер (на базе готового AV Engine), который должен быть устойчив к любому содержимому файлопомойки, так что не по наслышке знаю.

Для самоделки рекурсивной достаточно 1-2 тысяч вложенных каталогов, что-бы исчерпать лимит дескрипторов, если на каждом уровне держать открытый хендл (DIR*) директории, и вполне можно нарваться на срыв стека, если на каждом из уровней - перечитывать все содержимое каталога, так что тут нужно что-то очень гармоничное-продуманное, иначе — no way, fts_open наше все.

hydraulicbrakefluid
()
Ответ на: комментарий от Boy_from_Jungle

(=

Я просто попытался угадать, может это задание какое-то =)

Не-не-не вообще не троллю =)

Разве что оффтопики генерирую =)

m4n71k0r
()
Ответ на: комментарий от pathfinder

>Может популярно объяснишь, за счет чего можно достичь константного потребления памяти при обходе неупорядоченного дерева директорий произвольного размера?

очевидно, за счет изменения представоения дерева. например, в виде массива(списка)

yaws
()
Ответ на: комментарий от Boy_from_Jungle

Перевод на С++ и останов всего этого дела оставляю тебе

package org.absurd.mtfswalker;

import java.io.File;
import java.util.LinkedList;

public class Startup {
	static class Queue {
		private LinkedList queue = new LinkedList();
		
		synchronized void put(File file) {
			queue.addLast(file);
			notifyAll();
		}
		
		synchronized File get() throws InterruptedException {
			while (queue.isEmpty()) {
				wait();
			}
			return (File) queue.removeFirst();
		}
	}
	
	static final Queue QUEUE = new Queue();
	
	static class Worker implements Runnable {
		public void run() {
			try {
				while (true) {
					File f = QUEUE.get();
					if (f.isDirectory()) {
						File[] fileList = f.listFiles();
						for (int i = 0; i < fileList.length; i++) {
							if (fileList[i].isDirectory()) {
								QUEUE.put(fileList[i]);
							} else {
								System.out.println("Worker : " + Thread.currentThread().getName() 
										+ " visiting file " + fileList[i].getName());
							}
						}
					}
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}
	
	static final int WORKER_COUNT = 4;
	
	public static void main(String[] arg) {
		for (int i = 0; i != WORKER_COUNT; ++i) {
			new Thread(new Worker(), "WORKER_" + i).start();
		}
		QUEUE.put(new File("."));
	}
}
Absurd ★★★
()
Ответ на: комментарий от Bad_Habit

>На Qt такая задачка решается даже без фантазии.

Вот за это и не люблю Qt. Был графический тулкит, а в него понатаскали все, что только возможно.

Напрямую противоречит Unix way: библиотека выполняет одну функцию, но делает это хорошо.

ttnl ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.