powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничная huge-сортировка
8 сообщений из 133, страница 6 из 6
Тяпничная huge-сортировка
    #39420146
д0kХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonд0kХЭто я к тому что на скорость дискового ввода вывода и баланса нагрузок
может влиять даже место размещения файлов на поверхрости шпинделя
center - самое быстрое позиционирование
inner edge и outer edge более медленное позиционирование.
в center укладываются файлы с рандомным характером доступа ,
в edge с последовательным.
Я учту это замечание на будущее. Но давай пока стартанём просто
с разделов в /ext3, ext4 без привязки в расстоянию до шпинделя.

Допилим чуть позже когда будет более-менее работающий код.

В алгориме триплетов, каждый триплет будет создать неодинаковую
нагрузку. Потоки читатели будут делить по 50% трафика а поток-писатель
будет делать почти "горизонтальную полку" и оптимизировать это сейчас
сложно т.к. на следующем step фазы №2 их роли меняются и тот файл
который был создан писателем станет снова читаемым. И ситуация
перевернётся. Как быстро двигать файлы по поверхности шпинделя
так чтобы это не влияло на основной алгоитм - я пока не знаю.


Движение файла по поверхности имеет смысл если это файл
известной структуры с которого читается и в нем же делаются изменения.
темповые файлы двигать по поверхности смысла не имеет.

правила размещения простые , мелкие темповые файлы ложатся в центр ,
большие и результат ближе к edge.
...
Рейтинг: 0 / 0
Тяпничная huge-сортировка
    #39421011
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Затестил дерево триплетов на массивах 20303177 . Копирование в разы меньше других, т.е. переливание всего массива 1-2 раза. Сравнений сопоставимо с другими алгоритмами.
Т.е. для биг файла самое то что надо.
...
Рейтинг: 0 / 0
Тяпничная huge-сортировка
    #39421087
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TЗатестил дерево триплетов на массивах 20303177 . Копирование в разы меньше других, т.е. переливание всего массива 1-2 раза. Сравнений сопоставимо с другими алгоритмами.
Т.е. для биг файла самое то что надо.

На мой взгляд, дерево не самый лучший выбор.
Фактически чтение происходит по одной записи из случайного файла (или части файла).
Алгоритм более-менее работает только за счет блокирования и опережающего чтения ОС.

Пирамида подошла бы лучше.
На этапе загрузки данных в пирамиду читаем большими блоками записей.
Сначала по одному блоку из каждого файла (или части файла),
потом читаем очередной блок оттуда, где текущий ключ меньше.
Выгружаем пирамиду до минимального текущего ключа или полностью, если файлы исчерпаны.
...
Рейтинг: 0 / 0
Тяпничная huge-сортировка
    #39425119
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не впадая с указателями в погоню за гигфлоппами решение на языке высокого уровня.
ИМХО для сравнения приемлемое.
Студентам не показывать.


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
// Copyright 2017 by Mikron
// This piece of code distributed under terms of BSD License and without any warranty.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace MergeSort
{
    class Program
    {

        const int MAX_TEMP_FILES = 14;                  // Prefered size must be 2^n - 2, n > 1
        const int MAX_HEAP_SIZE = (1 << 16) - 1;        // Adjust accordingly to available memmory 

        static readonly Comparison<string> StringComparison = string.CompareOrdinal;
        static readonly Comparison<IEnumerator<string>> StringEnumeratorComparison = (x, y) => string.CompareOrdinal(x.Current, y.Current);

        static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                Console.WriteLine("Usage: {0} <source:_file> <target_file>");
                return;
            }
            var target = new Lazy<FileStream>[MAX_TEMP_FILES / 2];
            var source = new Lazy<FileStream>[MAX_TEMP_FILES - target.Length];
            try
            {
                Func<FileStream> createTempFile = () => new FileStream(Path.GetTempFileName(), FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
                for (var i = 0; i < target.Length; i += 1)
                {
                    target[i] = new Lazy<FileStream>(createTempFile);
                }
                for (var i = 0; i < source.Length; i += 1)
                {
                    source[i] = new Lazy<FileStream>(createTempFile);
                }
                int splitter;
                var timer = new Stopwatch();
                timer.Start();
                using (var sourceFile = new FileStream(args[0], FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    splitter = Split(MAX_HEAP_SIZE, ReadLines(sourceFile), source);
                }
                int runNo = 0;
                while (splitter > 1)
                {
                    var sourceReq = from s in source select ReadLines(s.Value);
                    splitter = Split(MAX_HEAP_SIZE, Merge(sourceReq.ToArray()), target);
                    var swapTmp = source;
                    source = target;
                    target = swapTmp;
                    foreach (var f in target)
                    {
                        if (f.IsValueCreated)
                        {
                            f.Value.Seek(0, SeekOrigin.Begin);
                            f.Value.SetLength(0);
                        }
                    }
                    runNo += 1;
                }
                timer.Stop();
                Console.WriteLine("Total number of Split/Merge runs: {0,8} in {1} ", runNo, timer.Elapsed);

                source[0].Value.Close();
                File.Move(source[0].Value.Name, args[1]);
                source[0].Value.Dispose();
                source[0] = null;
            }
            finally
            {
                Action<Lazy<FileStream>> cleanUp = (f) =>
                {
                    if (f != null && f.IsValueCreated)
                    {
                        f.Value.Close();
                        File.Delete(f.Value.Name);
                        f.Value.Dispose();
                    }
                };
                foreach (var f in source)
                    cleanUp(f);
                foreach (var f in target)
                    cleanUp(f);
            }
        }

        static IEnumerable<string> ReadLines(FileStream fileStream)
        {
            fileStream.Seek(0, SeekOrigin.Begin);
            using (var reader = new StreamReader(fileStream, Encoding.Default, true, 4096, true))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                    yield return line;
            }
        }

        static int Split(int heapCapacity, IEnumerable<string> source, Lazy<FileStream>[] destination)
        {
            var heap = new string[heapCapacity];
            var writers = new StreamWriter[destination.Length];
            int targets = 0;
            var ii = source.GetEnumerator();
            try
            {
                int writerIndex = 0;
                long numberOfReadLines = 0L;
                long numberOfSwitches = 0L;
                long longestStrip = 0L;
                long shortestStrip = long.MaxValue;
                int heapSize = 0;
                while (true)
                {
                    // Fill heap
                    while (heapSize < heapCapacity && ii.MoveNext())
                    {
                        heap[heapSize] = ii.Current;
                        BubbleUp(heap, heapSize, StringComparison);
                        heapSize += 1;
                    }
                    if (heapSize == 0)
                        break;
                    // Prepare for wrining next strip
                    long stripLength = 0L;
                    var writer = writers[writerIndex];
                    if (writer == null)
                    {
                        targets += 1;
                        var stream = destination[writerIndex].Value;
                        stream.Seek(0, SeekOrigin.Begin);
                        stream.SetLength(0);
                        writer = writers[writerIndex] = new StreamWriter(stream, Encoding.Default, 4096, true);
                    }
                    writerIndex = (writerIndex + 1) % writers.Length;

                    // Process lines
                    string priorLine = null;
                    while (true)
                    {
                        var line = heap[0];
                        var gapPos = RemoveHead(heap, heapSize, StringComparison);
                        if (priorLine != null && StringComparison(priorLine, line) > 0)
                        {
                            // Here I can be sure, all other elements in heap are above of priorLine
                            // So just flush them out and put line again in heap for begining of the next strip
                            heap[gapPos] = heap[--heapSize];
                            BubbleUp(heap, gapPos, StringComparison);
                            priorLine = line;       
                            break;
                        }
                        writer.WriteLine(line);
                        stripLength += 1L;
                        priorLine = line;
                        if (!ii.MoveNext())
                        {
                            heap[gapPos] = heap[--heapSize];
                            BubbleUp(heap, gapPos, StringComparison);
                            priorLine = null;       // Don't put prior line into heap again
                            break;
                        }
                        heap[gapPos] = ii.Current;
                        BubbleUp(heap, gapPos, StringComparison);
                    }

                    // Empty heap
                    if (heapSize > 0)
                    {
                        stripLength += heapSize;
                        while (true)
                        {
                            writer.WriteLine(heap[0]);
                            var gapPos = RemoveHead(heap, heapSize, StringComparison);
                            if (--heapSize <= 0)
                                break;
                            heap[gapPos] = heap[heapSize];
                            BubbleUp(heap, gapPos, StringComparison);
                        }
                    }
                    longestStrip = Math.Max(longestStrip, stripLength);
                    shortestStrip = Math.Min(shortestStrip, stripLength);
                    numberOfReadLines += stripLength;
                    numberOfSwitches += 1;
                    if (priorLine != null)
                    {
                        heap[heapSize] = priorLine;
                        BubbleUp(heap, heapSize, StringComparison);
                        heapSize += 1;
                    }
                }
                Console.WriteLine("Lines {0,8} Switches {1,8} Strip Min {2,8} Max {3,8} Avg {4,9:F5}", numberOfReadLines, numberOfSwitches,
                    shortestStrip, longestStrip, numberOfReadLines / (double) numberOfSwitches);
            }
            finally
            {
                ii.Dispose();
                foreach(var w in writers)
                {
                    if (w != null)
                        w.Dispose();
                }
            }
            return targets;
        }

        static int Split(IEnumerable<string> source, Lazy<FileStream>[] destination)
        {
            var writers = new StreamWriter[destination.Length];
            int targets = 0;
            try
            {
                int writerIndex = 0;
                StreamWriter writer = null;
                long numberOfReadLines = 0L;
                long numberOfSwitches = 0L;
                long longestStrip = 0L;
                long shortestStrip = long.MaxValue;
                long stripLength = 0L;
                string priorLine = null;
                foreach (var line in source)
                {
                    numberOfReadLines += 1;
                    if (writer == null || string.CompareOrdinal(priorLine, line) > 0)
                    {
                        if (stripLength > 0)
                        {
                            longestStrip = Math.Max(longestStrip, stripLength);
                            shortestStrip = Math.Min(shortestStrip, stripLength);
                        }
                        stripLength = 0L;
                        numberOfSwitches += 1;
                        writer = writers[writerIndex];
                        if (writer == null)
                        {
                            targets += 1;
                            var stream = destination[writerIndex].Value;
                            stream.Seek(0, SeekOrigin.Begin);
                            stream.SetLength(0);
                            writer = writers[writerIndex] = new StreamWriter(stream, Encoding.Default, 4096, true);
                        }
                        writerIndex = (writerIndex + 1) % writers.Length;
                    }
                    priorLine = line;
                    writer.WriteLine(line);
                    stripLength += 1L;
                }
                longestStrip = Math.Max(longestStrip, stripLength);
                shortestStrip = Math.Min(shortestStrip, stripLength);
                Console.WriteLine("Lines {0,8} Switches {1,8} Strip Min {2,8} Max {3,8} Avg {4,9:F5}", numberOfReadLines, numberOfSwitches,
                    shortestStrip, longestStrip, numberOfReadLines / (double)numberOfSwitches);
            }
            finally
            {
                foreach (var w in writers)
                {
                    if (w != null)
                        w.Dispose();
                }
            }
            return targets;
        }

        static IEnumerable<string> Merge(params IEnumerable<string>[] sources)
        {
            if (sources == null || sources.Length == 0)
                yield break;
            // Init heap
            var heap = new IEnumerator<string>[sources.Length];
            var length = 0;
            for (int i = 0; i < sources.Length; i += 1)
            {
                var s = sources[i].GetEnumerator();
                if (!s.MoveNext())
                {
                    s.Dispose();
                }
                else
                {
                    heap[length] = s;
                    BubbleUp(heap, length, StringEnumeratorComparison);
                    length += 1;
                }
            }
            // Enumerate
            while(true)
            {
                var s = heap[0];
                yield return s.Current;
                var gapPos = RemoveHead(heap, length, StringEnumeratorComparison);
                if (!s.MoveNext())
                {
                    s.Dispose();
                    if (--length <= 0)
                        break;
                    s = heap[length];
                }
                heap[gapPos] = s;
                BubbleUp(heap, gapPos, StringEnumeratorComparison);
            }
        }


        static int RemoveHead<T>(T[] heap, int length, Comparison<T> comparer)
        {
            int gap = 0;
            while (true)
            {
                var child = 1 + (gap << 1);
                if (child >= length)
                    break;
                if (child + 1 < length && comparer(heap[child], heap[child + 1]) >= 0)
                {
                    child += 1;
                }
                heap[gap] = heap[child];
                gap = child;
            }
            return gap;
        }

        static int BubbleUp<T>(T[] heap, int i, Comparison<T> comparer)
        {
            var s = heap[i];
            while (i > 0)
            {
                int parent = (i - 1) >> 1;
                if (comparer(heap[parent], s) < 0)
                    break;
                heap[i] = heap[parent];
                heap[parent] = s;
                i = parent;
            }
            return i;
        }

    }
}


...
Рейтинг: 0 / 0
Тяпничная huge-сортировка
    #39425278
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mikron, спасибо.
...
Рейтинг: 0 / 0
Тяпничная huge-сортировка
    #39425402
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алгоритм кстати не оптимальный.
Используется две кучи/пирамиды: первая для слияния данных из многих источников и образования единого потока данных,
вторая для сортировки потока данных в памяти.
Заметил важную деталь:
Использование второй кучи/пирамиды только вредит, т.к. увеличивает затраты на сравнения но улутшает длину сортированной последовательности только на +размер кучи за проход.
Основная же "ошибка" если так можно сказать в том что слияние потоков всегда берёт наименьшее текущее значение из всех потоков.
...
Рейтинг: 0 / 0
Тяпничная huge-сортировка
    #39425409
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тестовый файл сортировался 50 минут с 62 временными файлами и буфером на 2^18 строк. Т.к. Строки короткие это соответсвует 16 Мб памяти.
...
Рейтинг: 0 / 0
Тяпничная huge-сортировка
    #39425493
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Последние штрихи и можно сравнивать, с C++

// splitter = Split(MAX_HEAP_SIZE, Merge(sourceReq.ToArray()), target);
splitter = Split(Merge(sourceReq.ToArray()), target);

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
        static IEnumerable<string> Merge(params IEnumerable<string>[] sources)
        {
            if (sources == null || sources.Length == 0)
                yield break;
            // Init heap
            var heap = new IEnumerator<string>[sources.Length];
            var size = 0;
            for (int i = 0; i < sources.Length; i += 1)
            {
                var s = sources[i].GetEnumerator();
                if (!s.MoveNext())
                {
                    s.Dispose();
                }
                else
                {
                    heap[size] = s;
                    BubbleUp(heap, size, StringEnumeratorComparison);
                    size += 1;
                }
            }
            // Enumerate
            var nextHeap = new IEnumerator<string>[size];
            while (true)
            {
                var nextSize = 0;
                while (true)
                {
                    var h = heap[0];
                    var s = h.Current;
                    yield return s;
                    var gapPos = RemoveHead(heap, size, StringEnumeratorComparison);
                    if (!h.MoveNext())
                    {
                        h.Dispose();
                        if (--size <= 0)
                            break;
                        h = heap[size];
                    }
                    else if (StringComparison(h.Current, s) < 0)
                    {
                        nextHeap[nextSize] = h;
                        BubbleUp(nextHeap, nextSize, StringEnumeratorComparison);
                        nextSize += 1;
                        if (--size <= 0)
                            break;
                        h = heap[size];
                    }
                    heap[gapPos] = h;
                    BubbleUp(heap, gapPos, StringEnumeratorComparison);
                }
                if (nextSize == 0)
                    break;
                size = nextSize;
                var tmp = heap;
                heap = nextHeap;
                nextHeap = tmp;
            }
        }

...
Рейтинг: 0 / 0
8 сообщений из 133, страница 6 из 6
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничная huge-сортировка
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]