<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sort 1TB file]]></title><description><![CDATA[<p>Hi,</p>
<p>Wie kann man dieses Beispiel am effektivsten Loesen?</p>
<pre><code>Given a file of size 1TB, containing only 32 bit integers, describe how you would efficiently sort it. You have only 2GB of memory available.

1.) Teile die 1TB in 500 Chunks a. 2GB (1TB = 1000GB / 2GB = 500 Chunks)
    for i=0; i &lt; 500; i++
    	Lade Chunk_i (2GB) von der HDD in den RAM
	Sortiere Chunk_i mit Quicksort
	Schreibe den sortieren Chunk_i zurueck auf die HDD

    end

    Nun haben wir die Chunks a. 2GB sortiert

2.) 2 Way Sort
    - Allokiere 3.99MB x 500 Chunks als Eingangsbuffer
    - Allokiere 3.99 MB als Ausgansbuffer

    - Lese die ersten 3.99MB von jedem Chunk in den Eingangsbuffer
    - Merge den Eingangsbuffer in den Ausgangsbuffer, wenn Ausgangsbuffer voll ist -&gt; flush to HDD

Ein groesserer Ausgangsbuffer sollte die Performance erhoehen, da Schreiben auf die HDD langsam ist.
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/topic/325658/sort-1tb-file</link><generator>RSS for Node</generator><lastBuildDate>Sat, 11 Jul 2026 23:00:46 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/325658.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 12 May 2014 13:58:42 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Sort 1TB file on Mon, 12 May 2014 13:58:42 GMT]]></title><description><![CDATA[<p>Hi,</p>
<p>Wie kann man dieses Beispiel am effektivsten Loesen?</p>
<pre><code>Given a file of size 1TB, containing only 32 bit integers, describe how you would efficiently sort it. You have only 2GB of memory available.

1.) Teile die 1TB in 500 Chunks a. 2GB (1TB = 1000GB / 2GB = 500 Chunks)
    for i=0; i &lt; 500; i++
    	Lade Chunk_i (2GB) von der HDD in den RAM
	Sortiere Chunk_i mit Quicksort
	Schreibe den sortieren Chunk_i zurueck auf die HDD

    end

    Nun haben wir die Chunks a. 2GB sortiert

2.) 2 Way Sort
    - Allokiere 3.99MB x 500 Chunks als Eingangsbuffer
    - Allokiere 3.99 MB als Ausgansbuffer

    - Lese die ersten 3.99MB von jedem Chunk in den Eingangsbuffer
    - Merge den Eingangsbuffer in den Ausgangsbuffer, wenn Ausgangsbuffer voll ist -&gt; flush to HDD

Ein groesserer Ausgangsbuffer sollte die Performance erhoehen, da Schreiben auf die HDD langsam ist.
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2398818</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398818</guid><dc:creator><![CDATA[QuickSort]]></dc:creator><pubDate>Mon, 12 May 2014 13:58:42 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Mon, 12 May 2014 14:00:18 GMT]]></title><description><![CDATA[<p>der Text nach der Frage, sollte mein Ansatz sein. Wie waehlt die optimale Groesse des Ausgangsbuffers?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398819</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398819</guid><dc:creator><![CDATA[QuickSort]]></dc:creator><pubDate>Mon, 12 May 2014 14:00:18 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Mon, 12 May 2014 22:51:21 GMT]]></title><description><![CDATA[<p>Zu 1: Beachte, dass Quicksort nicht in-place sortiert. Also musst du entweder ein anderes Sortierverfahren wählen oder die Chunks etwas kleiner machen.</p>
<blockquote>
<p>Wie waehlt die optimale Groesse des Ausgangsbuffers?</p>
</blockquote>
<p>Das ist in erster Linie eine Frage der unterliegenden Hardware. Wie sich Schreib- und Lesezugriffe zueinander verhalten, ob und wie die Hardware parallelisiert ist und vieles andere. Ja, es kann sehr gut möglich sein, dass ein größerer Ausgangspuffer besser ist. Aber welche Größe genau die richtige ist, kann man ohne weitere Information nicht sagen. Man kann höchstens einen Aufsatz darüber schreiben, welche Faktoren die Wahl wie beeinflussen. Ein solcher Aufsatz steht auf Wikipedia, welchen du sicherlich schon gelesen hast, oder?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398910</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398910</guid><dc:creator><![CDATA[SeppJ]]></dc:creator><pubDate>Mon, 12 May 2014 22:51:21 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Mon, 12 May 2014 23:47:24 GMT]]></title><description><![CDATA[<p>Wahrscheinlich bietet es sich hier an, gar nicht groß zu sortieren, sondern zu zählen, wie oft jede einzelne Zahl vorkommt (um lineare Laufzeitkomplexität zu erreichen). Die begrenzte Zustandsmenge eines 32-Bit-Integers erlaubt das hier.</p>
<p>Das lässt sich besonders effektiv gestalten, wenn man vorher den Wertebereich der Integer abschätzen kann und dieser ausreichend klein ist (beispielsweise nur Zahlen zwischen -2<sup>26</sup> und 2<sup>26</sup>), sollte aber auch so ganz gut handhabbar sein.</p>
<p>Ich denke mir das etwa so, dass man eine große Datei von 32 Gigabyte Größe anlegt (8 Byte Zähler mal 2<sup>32</sup> mögliche Werte, anfänglich mit Nullen voll) und eine große Hashmap (mit so nem Gigabyte Platz) im Speicher hat, in der man zu den bereits gefundenen Werten nen Zähler hat, wie oft man sie gefunden hat. Wenn die Hashmap überläuft (Einstellungssache -- sinnigerweise dann, wenn man anfängt, mit vielen Kollisionen zu kämpfen. Pi mal Faust bei 80% Auslastung oder so, wenn die Daten nicht komisch strukturiert sind) läuft man einmal über die Hashmap, addiert die neuen Zähler auf die bereits vorhandenen Zähler in der großen Datei, wirft den den Inhalt der Hashmap weg und macht mit den nächsten paar Gigabyte das selbe wieder.</p>
<p>Danach hat man eine Datei, in der zu jedem 32-Bit-Wert steht, wie oft er in der Ursprungsdatei war (quasi eine Art rudimentäres RLE). Die wäre in vielen Fällen vermutlich angenehmer zu benutzen, aber wenn man wirklich eine große Datei braucht, in der die Zahlen sortiert ausgeschrieben hintereinander stehen, ist die von da an leicht zu erzeugen, indem man aus der RLE-Datei nacheinander die Zähler ausliest und entsprechend viele korrespondierende Zahlen in eine weitere Datei rausschreibt.</p>
<p>Dabei könnte es von Vorteil sein, die RLE-Datei auf einer SSD zu erzeugen, wenn einen die Abnutzung derselbigen nicht stört, und sparse files zu benutzen, wenn große Löcher in der Wertemenge erwartet werden. Obwohl bei einem Terabyte an Daten es wahrscheinlich nicht mehr so ins Gewicht fiele, anfangs 32 GB Nullen in eine Datei zu schreiben und sie am Stück zu haben, was auch von Vorteil sein könnte. Müsste man ausprobieren und nachmessen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398913</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398913</guid><dc:creator><![CDATA[seldon]]></dc:creator><pubDate>Mon, 12 May 2014 23:47:24 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Mon, 12 May 2014 23:51:51 GMT]]></title><description><![CDATA[<p>Nachtrag:</p>
<p>Das ist natürlich sehr speziell auf 32-Bit-Integer zugeschnitten. Bei 64-Bit-Integern wäre es schon nicht mehr praktikabel, und wenn es um komplexere Daten geht, ist man mit dem Ansatz eh verloren. Worauf die mit der Aufgabe hinaus wollen, da hast du wahrscheinlich recht, wird eher merge sort sein.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398914</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398914</guid><dc:creator><![CDATA[seldon]]></dc:creator><pubDate>Mon, 12 May 2014 23:51:51 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 00:15:19 GMT]]></title><description><![CDATA[<p>SeppJ schrieb:</p>
<blockquote>
<p>Zu 1: Beachte, dass Quicksort nicht in-place sortiert.</p>
</blockquote>
<p>Huch? Seit wann?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398915</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398915</guid><dc:creator><![CDATA[Jester]]></dc:creator><pubDate>Tue, 13 May 2014 00:15:19 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 00:56:27 GMT]]></title><description><![CDATA[<p>Jester schrieb:</p>
<blockquote>
<p>SeppJ schrieb:</p>
<blockquote>
<p>Zu 1: Beachte, dass Quicksort nicht in-place sortiert.</p>
</blockquote>
<p>Huch? Seit wann?</p>
</blockquote>
<p>Schon immer? Wo speicherst du denn die &quot;Laufvariablen&quot; der Rekursion?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398916</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398916</guid><dc:creator><![CDATA[SeppJ]]></dc:creator><pubDate>Tue, 13 May 2014 00:56:27 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 04:13:58 GMT]]></title><description><![CDATA[<p>1. 2GB in den Arbeitsspeicher zu laden, wenn du nur 2GB hast, ist nicht gut.</p>
<p>Musst du das File überschreiben oder darfst du ein neues anlegen und ist der HDD Platz gegrenzt?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398921</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398921</guid><dc:creator><![CDATA[ggtt]]></dc:creator><pubDate>Tue, 13 May 2014 04:13:58 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 06:39:03 GMT]]></title><description><![CDATA[<p>SeppJ schrieb:</p>
<blockquote>
<p>Jester schrieb:</p>
<blockquote>
<p>SeppJ schrieb:</p>
<blockquote>
<p>Zu 1: Beachte, dass Quicksort nicht in-place sortiert.</p>
</blockquote>
<p>Huch? Seit wann?</p>
</blockquote>
<p>Schon immer? Wo speicherst du denn die &quot;Laufvariablen&quot; der Rekursion?</p>
</blockquote>
<p><a href="https://en.wikipedia.org/wiki/Quicksort" rel="nofollow">https://en.wikipedia.org/wiki/Quicksort</a> schrieb:</p>
<blockquote>
<p>Quicksort can be implemented with an in-place partitioning algorithm, so the entire sort can be done with only O(log n) additional space used by the stack during the recursion.[2]</p>
</blockquote>
]]></description><link>https://www.c-plusplus.net/forum/post/2398927</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398927</guid><dc:creator><![CDATA[nwp3]]></dc:creator><pubDate>Tue, 13 May 2014 06:39:03 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 06:52:43 GMT]]></title><description><![CDATA[<p>nwp3 schrieb:</p>
<blockquote>
<p><a href="https://en.wikipedia.org/wiki/Quicksort" rel="nofollow">https://en.wikipedia.org/wiki/Quicksort</a> schrieb:</p>
<blockquote>
<p>Quicksort can be implemented with an in-place partitioning algorithm, so the entire sort can be done with only O(log n) additional space used by the stack during the recursion.[2]</p>
</blockquote>
</blockquote>
<p>in-place := O(1) additional space</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398930</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398930</guid><dc:creator><![CDATA[Bashar]]></dc:creator><pubDate>Tue, 13 May 2014 06:52:43 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 08:37:59 GMT]]></title><description><![CDATA[<p>zu Punkt1: QuickSort in-place <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398938</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398938</guid><dc:creator><![CDATA[QuickSort]]></dc:creator><pubDate>Tue, 13 May 2014 08:37:59 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 08:41:39 GMT]]></title><description><![CDATA[<p>Ich finde seldon's Ansatz sehr gut <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f44d.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--thumbs_up"
      title=":+1:"
      alt="👍"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398940</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398940</guid><dc:creator><![CDATA[Revolution]]></dc:creator><pubDate>Tue, 13 May 2014 08:41:39 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 10:47:20 GMT]]></title><description><![CDATA[<p>seldon schrieb:</p>
<blockquote>
<p>Wahrscheinlich bietet es sich hier an, gar nicht groß zu sortieren, sondern zu zählen, wie oft jede einzelne Zahl vorkommt (um lineare Laufzeitkomplexität zu erreichen). Die begrenzte Zustandsmenge eines 32-Bit-Integers erlaubt das hier.</p>
</blockquote>
<p>Die Idee hatte ich auch, hab ich dann aber nach näherer Betrachtung wieder verworfen.</p>
<p>seldon schrieb:</p>
<blockquote>
<p>Ich denke mir das etwa so, dass man eine große Datei von 32 Gigabyte Größe anlegt (8 Byte Zähler mal 2<sup>32</sup> mögliche Werte, anfänglich mit Nullen voll) und eine große Hashmap (mit so nem Gigabyte Platz) im Speicher hat, in der man zu den bereits gefundenen Werten nen Zähler hat, wie oft man sie gefunden hat. Wenn die Hashmap überläuft (Einstellungssache -- sinnigerweise dann, wenn man anfängt, mit vielen Kollisionen zu kämpfen. Pi mal Faust bei 80% Auslastung oder so, wenn die Daten nicht komisch strukturiert sind) läuft man einmal über die Hashmap, addiert die neuen Zähler auf die bereits vorhandenen Zähler in der großen Datei, wirft den den Inhalt der Hashmap weg und macht mit den nächsten paar Gigabyte das selbe wieder.</p>
</blockquote>
<p>Und genau beim &quot;Integrieren&quot; der Hashmap (=Zählerwerte auf das File draufaddieren) wirst du Performance-Probleme bekommen.<br />
Entweder du gehst die Hashmap in ihrer &quot;nativen&quot; Reihenfolge durch, dann bringen dich die Random-IOs auf das File um.<br />
Oder du gehst das File linear durch, dann musst du 4 Mio. Zugriffe auf die Hashmap machen um die passenden Werte zu finden.</p>
<p>=&gt; Eher noch ne Baum-basierte Map. Damit könnte man beim &quot;Integrieren&quot; die Map durchiterieren und gleichzeitig linear auf das File zugegreifen.</p>
<p>Ich erwarte mir aber dass auch das im &quot;average case&quot; wesentlich langsamer sein wird als die Datei in z.B. 1 GB Stücke zu zerteilen, diese dann mit Quicksort zu sortieren, und am Ende dann zusammenzumergen.</p>
<p>Bei der Lösung musst du 1x das File komplett lesen und schreiben für den Quicksort, und dann nochmal komplett lesen und schreiben für den Merge.<br />
Alle Zugriffe für den Quicksort sind linear. Die Zugriffe beim Mergen sind nicht mehr so ganz linear, aber man kann zumindest immer grössere Stücke auf einmal bearbeiten - zumindest 1 MB Stücke gehen sich aus. Und Random IO mit 1 MB Blocks ist fast gleich schnell wie linear.</p>
<p>=&gt; Die Quicksort =&gt; Merge Methode wird schwer zu schlagen sein.</p>
<p>Bashar schrieb:</p>
<blockquote>
<p>nwp3 schrieb:</p>
<blockquote>
<p><a href="https://en.wikipedia.org/wiki/Quicksort" rel="nofollow">https://en.wikipedia.org/wiki/Quicksort</a> schrieb:</p>
<blockquote>
<p>Quicksort can be implemented with an in-place partitioning algorithm, so the entire sort can be done with only O(log n) additional space used by the stack during the recursion.[2]</p>
</blockquote>
</blockquote>
<p>in-place := O(1) additional space</p>
</blockquote>
<p>Die Definition mag &quot;mathematisch korrekt&quot; sein, ist davon abgesehen aber total irrelevant.</p>
<p>Ich bezeichne Sachen die mit <code>O(log N)</code> Zwischenspeicher auskommen auch als &quot;in place&quot;.<br />
log2 von 1 yotta ist z.B. ca. 80. Rekursionstiefe 80 ist normalerweise kein Problem, da man normalerweise genug Stack dafür hat. Und N ist normalerweise kleiner als 1 yotta.<br />
=&gt; Quicksort kann normalerweise als in-place angesehen werden.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398964</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398964</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Tue, 13 May 2014 10:47:20 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 11:25:07 GMT]]></title><description><![CDATA[<p>Statt [unordered_]map+counting könnte man auch einfach ≈2GB lesen + Quicksort + 32GB-File updaten. Wenn das 32GB-File fertig ist, kann man die sortierten ints in die Ausgabedatei rausschreiben.</p>
<p>Angenommen, dass Quicksort auf &lt;2GB gleich schnell geht wie das Lesen von 2GB, und Lesen/Schreiben gleich schnell sind, entspricht die Laufzeit dem Lesen von 35 TB.</p>
<p>Die 32GB kann man auch auf 24GB reduzieren, dann hat man 27 TB.</p>
<p>Noch kompakter wären 4-Byte-Zähler und sich die Overflows in einem separaten File zu merken. Entspricht ungefähr 20 TB.</p>
<p>Quicksort + Merge ist etwas besser, angenommen die Suche nach dem Minimum aus den 400 Buffern dem Lesen von 6 Integern auf der HD entspricht, entspricht die Laufzeit des 400-Merges auf N Bytes dem Lesen von 8*N TB. Hat man das einmal auf die 1GB-Chunks gemacht hat man 2 sortierte 0.4TB-Chunks, nochmal gibt 1 TB. =&gt; (8+5+3)=16TB.</p>
<p>Gibt sich also nicht viel zwischen den verschiedenen Methoden.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398971</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398971</guid><dc:creator><![CDATA[yotta]]></dc:creator><pubDate>Tue, 13 May 2014 11:25:07 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 11:58:49 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p>Und genau beim &quot;Integrieren&quot; der Hashmap (=Zählerwerte auf das File draufaddieren) wirst du Performance-Probleme bekommen.<br />
Entweder du gehst die Hashmap in ihrer &quot;nativen&quot; Reihenfolge durch, dann bringen dich die Random-IOs auf das File um.<br />
Oder du gehst das File linear durch, dann musst du 4 Mio. Zugriffe auf die Hashmap machen um die passenden Werte zu finden.</p>
</blockquote>
<p>Da glaube ich nicht dran, wegen der geringeren Komplexitätsklasse. Für jeden Zähler ein fseek zu machen klingt zwar barbarisch, aber bei extrem großen Datenmengen skaliert es immer noch besser als die Sortierung.</p>
<p>hustbaer schrieb:</p>
<blockquote>
<p>=&gt; Eher noch ne Baum-basierte Map. Damit könnte man beim &quot;Integrieren&quot; die Map durchiterieren und gleichzeitig linear auf das File zugegreifen.</p>
</blockquote>
<p>Damit verlöre man die bessere Komplexitätsklasse. Das wäre ausgesprochen ungünstig.</p>
<p>...und um mich nicht unnötig zu wiederholen, meine Antwort auf den Rest ist auch nur &quot;Komplexitätsklasse.&quot; Skalieren wird es ungeachtet der fseeks besser, da der linear steigende I/O-Aufwand zunehmend hinter dem Sortieraufwand zurückbleibt. Die Frage ist höchstens, ob der Break-Even-Punkt bei einem Terabyte Daten erreicht wird. Intuitiv scheint es mir so, als sollte das der Fall sein (besonders, wenn die Datei auf einem Medium liegt, dem fseeks nicht viel ausmachen), ich habe aber gerade kein System zur Hand, auf der ich derart große Datenmengen herumschubsen könnte, um es zu messen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398977</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398977</guid><dc:creator><![CDATA[seldon]]></dc:creator><pubDate>Tue, 13 May 2014 11:58:49 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 13:14:20 GMT]]></title><description><![CDATA[<p><a href="http://de.wikipedia.org/wiki/Mergesort" rel="nofollow">http://de.wikipedia.org/wiki/Mergesort</a></p>
<p>Der 1. Schritt war OK. Der 2. muss etwas anders aussehen, ggf. per Kaskade loesen. D.h. nicht sofort die 500 sortierten Chunks zusammenfuegen, sondern die ersten 25, usw. und dann nochmal die resultierenden 20.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398988</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398988</guid><dc:creator><![CDATA[altmann]]></dc:creator><pubDate>Tue, 13 May 2014 13:14:20 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 13:33:44 GMT]]></title><description><![CDATA[<p>Kein Problem, dafür gibt's die <code>std::priority_queue</code> .</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2398991</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2398991</guid><dc:creator><![CDATA[prioq]]></dc:creator><pubDate>Tue, 13 May 2014 13:33:44 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 19:36:02 GMT]]></title><description><![CDATA[<p>Sagen wir wir bekommen 300 Mio. Zählerstände in die Hashmap. Viel mehr wird sich bei 2GB RAM nicht ausgehen.<br />
Wir können davon ausgehen dass keine Zugriffe auf die Zähler-Datei über den Cache bedient werden.<br />
D.h. 300 Mio. ungecachte IOs.<br />
Eine HDD schafft typischerweise so an die 100 IOs pro Sekunde, und das ist bereits mit Heimweh und Rückenwind.<br />
Macht 3 Mio. Sekunden.</p>
<p>Wenn alle 32 Bit Werte vorkommen müssen wir das mindestens 14x machen (wobei es ein Wunder wäre wenn man wirklich mit 14x auskommt)<br />
=&gt; 42 Mio. Sekunden.</p>
<p>Ich hab' keine Ahnung wie man ausrechnet wie oft man bei zufälliger Verteilung &quot;flushen&quot; müsste, aber es wird viel viel öfter als 14x sein.<br />
Ich runde einfach mal auf 100 Mio. auf, das wird es mindestens sein, und ist ne schöne runde Zahl.<br />
100 Mio. Sekunden sind mehr als 3 Jahre.</p>
<p>SSDs sind schneller. So ca. Faktor 1000, also 100.000 IOs pro Sekunde schaffen die. (Real wird weniger übrig bleiben, aber egal, geht ja nur um Grössenordnungen). Sind immer noch 1,15 Tage.</p>
<p>=&gt; Nein, ich glaube nicht dass das gut funktionieren wird.</p>
<p>Da gewinnt sogar noch eine andere, viel einfacher zu implementierende Zählvariante:<br />
Im 1. Durchgang die ersten 100 Mio. Werte zählen, im 2. Durchgang die nächsten 100 Mio. Werte ... =&gt; 44 Durchgänge.<br />
Wenn ein Durchgang linear mit 100 MB/s lesen kann, dann braucht er für 1 TB ca. 3 Stunden. x43 = 5,4 Tage.<br />
Ne SSD ist schneller, sagen wir an die 500 MB/s =&gt; 1,1 Tage.<br />
(Das Rausschreiben der Zählerstände spar ich mir, das geht unter. Genau so das Generieren des sortierten Files zum Schluss.)</p>
<p>Die Quicksort + Merge Lösung wird gefühlsmässig noch darunter liegen.</p>
<p>seldon schrieb:</p>
<blockquote>
<p>Komplexitätsklasse</p>
</blockquote>
<p>*gähn*<br />
Und google auch mal nach Performance-Vergleichen von Hashmaps vs. Treemaps. Die unterschiedliche Komplexitätsklasse ist da rein theoretisch. In der Praxis ist im RAM kaum ein Unterschied. Zumindest nicht bei gängigen Systemen mit gängigen RAM Grössen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2399006</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2399006</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Tue, 13 May 2014 19:36:02 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 23:07:14 GMT]]></title><description><![CDATA[<p>Ich halte es bei einer Datenmenge von 1TB nicht für angebracht, die Komplexitätsklasse mit &quot;*gähn*&quot; abzutun. 1TB Daten zu sortieren, das wird ne Weile dauern, ganz egal, wie du es anfängst, und &quot;Ansatz 1 dauert nen Tag, das ist mir zu lange&quot; belegt nicht, dass Ansätze 2 und 3 schneller laufen.</p>
<p>Das grundsätzlich. Ich hab jetzt mal nachgemessen, anstatt mir Zahlen zusammenzufantasieren, und du hast in Bezug auf eine Sache recht: Die seeks auf einer Festplatte kommen zu langsam. Nicht so langsam, wie du es einschätzt -- das pegelt sich in meiner Messung recht schnell bei so 1000 seek-read-seek-write-Zyklen pro Sekunde ein (Zugriffsstelle in der Datei jeweils zufällig ausgewürfelt), aber zu langsam für den use case. Abhängig von der Festplatte mag das variieren -- ich habe jetzt auf einer einzelnen consumer-hdd gemessen, wo in der Realität ein RAID wahrscheinlicher wäre -- aber wahrscheinlich nicht mehr als eine Größenordnung. Eine Messung auf SSD werde ich noch nachreichen, sobald ich wieder vor einer SSD sitze. Da das Zugriffsmuster für eine HDD sehr ungünstig ist und einer SSD geschwindigkeitstechnisch prinzipiell egal sein sollte (auch wenn es Gift für das wear-leveling ist), sollte uns das in realistischere Bereiche rücken.</p>
<p>So oder so ist das ein Problem, das man mit Bäumen nicht los wird. Dass man weniger Elemente darin unterkriegt, weil die Baumknoten verkettet werden müssen, ließe sich durch die Verwendung eines Heaps statt eines Baums noch regeln, aber in dem Fall, dass wirklich der gesamte Wertebereich des 32-Bit-Integers ausgefüllt würde, wären konsekutive Elemente in einem Baum ebenfalls sehr selten.</p>
<p>Da das aber auch bedeutet, und das ist mir zunächst auch nicht aufgefallen, dass die Zähler selten einen anderen Wert als 1 erreichen würden, das ganze Caching nicht so richtig sinnvoll. Wenn man Vermutungen über die Struktur der Wertemenge anstellen kann, sieht das u.U. anders aus.</p>
<p>Also, im Folgenden ohne Caching: Jede Zahl einzeln auf die RLE-Datei schlagen, das bedeutet 2<sup>38</sup> seek-read-seek-write-Zyklen, bedeutet mit meiner Festplatte 8,7 Jahre. Das ist nicht so richtig befriedigend. Wenn Faktor 1000 bei ner SSD richtig ist (Messung folgt noch), dann sind es 3 Tage und gut 4 Stunden, das wäre auf einer Node mit 2 GB verfügbarem RAM realistischer. Meine Vermutung ist aber, dass, weil Seeken der SSD echt egal ist, der Unterschied nochmal größer ausfallen wird. In einer Messung von Thomas Krenn einer Intel-SSD im Januar (Link weiter unten) zeigte sich da kein Unterschied zwischen sequentiellen und zufälligen Zugriffen, und wenn man die 8 Terabyte Zähler da wirklich mit 90 MB/s durchdübeln kann, reden wir nur noch von einem Tag. Das alles unter dem Vorbehalt einer Messung, die ich noch tun muss -- dummerweise bedeutet das, dass diese Hochrechnung nicht so richtig wertvoll ist.</p>
<p>Gegenrechnung Mergesort: Ich hab wieder mal gemessen. Auf meinem i7-4771 dauert ein std::sort (also ein Quicksort) von 1 GB Zufallsdaten ~21 Sekunden. Das muss man tausend mal machen, sind knapp 6 Stunden. zwei davon im RAM zu std::mergen dauert hier 0,41 Sekunden. Wenn man alles im Speicher halten könnte und durch sukzessives Mergen größere Vektoren zusammenbauen würde (immer zwei mergen), wäre man am Ende hochgerechnet eine halbe Stunde beschäftigt. Das alles im RAM zu halten ist natürlich illusorisch, wenn uns nur 2 GB zur Verfügung stehen. Nehmen wir - jetzt wird's dekadent - eine &gt;2 Terabyte-SSD als scratch space an, die einen Datendurchsatz von 250 MB/s Lesen und 90 MB/s Schreiben schafft (das sind Optimalwerte aus <a href="http://www.thomas-krenn.com/de/wiki/I/O_Performance_Vergleich_von_Festplatten_mit_SSDs_und_Fusion-io_ioDrive" rel="nofollow">einer Messung von Thomas Krenn im Januar</a>). Wir erzeugen ein Datenvolumen von 10 TB (10 Merge-Ebenen, für die jeweils der gesamte Content gelesen und geschrieben wird. Die naheliegende Idee, alles gleichzeitig zu mergen, skaliert mit O(n<sup>2</sup>) und wird langsamer sein), das macht 11 Stunden Lesen und 1 Tag und gut 6 Stunden Schreiben. Wir sind inzwischen bei 2 Tagen.</p>
<p>(jeweils plus das, was in beiden Fällen gemacht werden muss)</p>
<p>...</p>
<p>Jetzt muss ich diese verdammte SSD ausmessen. Was am Ende besser da stünde, kann ich jedenfalls nur mit solchen Überschlägen nicht vorhersagen. Könnte noch knapp vor break-even liegen.</p>
<p>Egal, was am Ende konkret schneller wäre, man kann sich bei solchen Datenmengen nicht mehr auf sein Gefühl verlassen -- vor allem, wenn sich das Gefühl vor allem um etwas dreht, das am Ende einen konstanten Faktor ausmacht. Den Daumen vor die Schnauze zu halten und zu sagen &quot;Komplexitätsklasse, gähn. Gefühlt muss der Mergesort da in zwei Stunden durch sein&quot; führt einen in die Irre. Der Haken ist genau</p>
<p>hustbaer schrieb:</p>
<blockquote>
<p>Zumindest nicht bei gängigen Systemen mit gängigen RAM Grössen.</p>
</blockquote>
<p>...wir reden hier nicht mehr von gängigen Größen.</p>
<p>Medallien-Kehrseite: Ich hab den Effekt des log(n)-Faktors größer eingeschätzt und hätte erwartet, dass der mergesort deutlich länger braucht. Den Schuh des getrügten Gefühls muss ich mir auch anziehen.</p>
<p>Der Elefant im Zimmer</p>
<p>Worauf wir jetzt noch überhaupt nicht eingegangen sind, ist der eigentliche Trick im Umgang mit solchen Datenmassen: Parallelisierung. Ich habe in der Aufgabenstellung jetzt keine Information darüber gesehen, wie viele Prozessorkerne der TE benutzen darf, aber letztendlich ist das Szenario der Aufgabe eh unrealistisch. Ich lass mal folgenden Link da:</p>
<p><a href="http://sortbenchmark.org/" rel="nofollow">http://sortbenchmark.org/</a></p>
<p>...und stelle anheim, dass derart große Datenmengen in der Praxis immer verteilt auf großen HPC-Clustern verarbeitet werden, wo man das in brauchbarer Zeit hinkriegt, und wo jede Node auch ausreichend RAM rumliegen hat, um nicht dauernd Dinge auf Platte schreiben zu müssen. Und da sortiert man dann auch ganz sicher nicht einfach nur Zahlen, womit sich die Zählerei sowieso erledigt hat.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2399080</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2399080</guid><dc:creator><![CDATA[seldon]]></dc:creator><pubDate>Tue, 13 May 2014 23:07:14 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Tue, 13 May 2014 23:17:56 GMT]]></title><description><![CDATA[<p>seldon schrieb:</p>
<blockquote>
<p><a href="http://sortbenchmark.org/" rel="nofollow">http://sortbenchmark.org/</a><br />
[...]<br />
Und da sortiert man dann auch ganz sicher nicht einfach nur Zahlen, womit sich die Zählerei sowieso erledigt hat.</p>
</blockquote>
<p>Der Indy-Benchmark macht genau das <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2399082</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2399082</guid><dc:creator><![CDATA[SeppJ]]></dc:creator><pubDate>Tue, 13 May 2014 23:17:56 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Wed, 14 May 2014 00:30:16 GMT]]></title><description><![CDATA[<p>Das Zählen ist lukrativ, weil jeder Wert im Durchschnitt 256 mal auftaucht.</p>
<p>Ich würde an Folgendes denken:<br />
Beim Mergen hat man Streams von Paaren mit (Wert;Anzahl), und die bei Ungleichheit wird wie gehabt das Paar mit dem kleineren Wert geschrieben und weggelesen, bei Gleichheit einfach ein Paar mit dem Wert und der Summe der Anzahlen geschrieben und beide weggelesen. Ich könnte mir vorstellen, daß damit das Schreibvolumen Stufe für Stufe gehörig eingedampft wird.</p>
<p>Ansonsten gehts's nur drum, auf der Drehplatte zu vermeiden, daß der Kamm dauernd lange Wege macht. Uih... Stets die 2G als Puffer verwenden, klar.<br />
Paarmal (8?) durchlaufen und nach ersten paar Bits sichten und Sichtungen rausschreiben. Hätte den Vorteil, daß die nächsten 8 Files am Stück wären. Nochmal machen, dann mergen? Unendlich viele Möglichkeiten.</p>
<p>Hat man zufällig drei Drehplatten? Dann könnte man immer von zweien auf die dritte mergen und hätte stets volle Bandbreite.</p>
<p>Mit SSDs in TB-Größe gehts's wieder anders.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2399083</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2399083</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Wed, 14 May 2014 00:30:16 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Wed, 14 May 2014 01:06:07 GMT]]></title><description><![CDATA[<p>seldon schrieb:</p>
<blockquote>
<p>Ich halte es bei einer Datenmenge von 1TB nicht für angebracht, die Komplexitätsklasse mit &quot;*gähn*&quot; abzutun.</p>
</blockquote>
<p>Mein Bauchgefühl sagt mir, dass es hier angebracht ist <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /><br />
Daher das &quot;*gähn*&quot; - weil du mMn. auf etwas rumreitest dass bei genau der gegebenen Aufgabenstellung irrelevant ist. (Also so lange es um den Unterschied Quicksort + &quot;breitem&quot; Merge vs. O(N) geht -- bei &quot;schlimmerem&quot; als Quicksort würden wir vermutlich wirklich ein Problem bekommen.)</p>
<p>seldon schrieb:</p>
<blockquote>
<p>1TB Daten zu sortieren, das wird ne Weile dauern, ganz egal, wie du es anfängst, und &quot;Ansatz 1 dauert nen Tag, das ist mir zu lange&quot; belegt nicht, dass Ansätze 2 und 3 schneller laufen.</p>
</blockquote>
<p>Ich müsste es ausprobieren, aber wieder: mein Bauchgefühl sagt mir dass es in deutlich weniger als einem Tag geht. So lange man es cachefreudnlich implementiert, und sowohl Quicksort als auch Mergesort sind cachefreudnlich (ich hoffe, es ist spät, ich kann nicht mehr denken, hihi).</p>
<p>seldon schrieb:</p>
<blockquote>
<p>Ich hab jetzt mal nachgemessen, anstatt mir Zahlen zusammenzufantasieren, und du hast in Bezug auf eine Sache recht: Die seeks auf einer Festplatte kommen zu langsam. Nicht so langsam, wie du es einschätzt -- das pegelt sich in meiner Messung recht schnell bei so 1000 seek-read-seek-write-Zyklen pro Sekunde ein (Zugriffsstelle in der Datei jeweils zufällig ausgewürfelt), aber zu langsam für den use case.</p>
</blockquote>
<p>Also hier sagt mir meine Erfahrung dass das nicht sein kann. Hast du mit einem File gemessen das - so wie im Beispiel - viel viel grösser als das als File-Cache zur Verfügung stehende RAM war?</p>
<p>seldon schrieb:</p>
<blockquote>
<p>Abhängig von der Festplatte mag das variieren -- ich habe jetzt auf einer einzelnen consumer-hdd gemessen, wo in der Realität ein RAID wahrscheinlicher wäre -- aber wahrscheinlich nicht mehr als eine Größenordnung.</p>
</blockquote>
<p>Mit RAID kannst du quasi beliebig skalieren - du brauchst nur genügend Platten. Aber bei nem Rechner mit 2 GB RAM ein fettes RAID anzunehmen... also das wäre schon etwas komisch.</p>
<p>seldon schrieb:</p>
<blockquote>
<p>Eine Messung auf SSD werde ich noch nachreichen, sobald ich wieder vor einer SSD sitze. Da das Zugriffsmuster für eine HDD sehr ungünstig ist und einer SSD geschwindigkeitstechnisch prinzipiell egal sein sollte (auch wenn es Gift für das wear-leveling ist), sollte uns das in realistischere Bereiche rücken.</p>
</blockquote>
<p>Ich hab' die Zahl nicht einfach aus der Luft gegriffen. Günstige SSDs schaffen alleine schon wegen dem &quot;langsamen&quot; SATA Bus nicht mehr als etwa 100K IOPS. Und das ist ohne read-modify-write, als muss man die Zahl sogar nochmal halbieren. Und wenn du es nicht optimierst läuft alles mit Queue-Depth 1, und die Performance stirbt dir komplett weg.</p>
<p>seldon schrieb:</p>
<blockquote>
<p>Wenn Faktor 1000 bei ner SSD richtig ist (Messung folgt noch), dann sind es 3 Tage und gut 4 Stunden, das wäre auf einer Node mit 2 GB verfügbarem RAM realistischer. Meine Vermutung ist aber, dass, weil Seeken der SSD echt egal ist, der Unterschied nochmal größer ausfallen wird.</p>
</blockquote>
<p>Siehe oben. Die 100K IPOS sind schon sehr hoch geschätzt. Und das ist bestenfalls &quot;nur&quot; Faktor 50 gegen die von dir gemessenen (und von mir bezweifelten *g*) 1000 Read-Modify-Write pro Sekunde.</p>
<p>seldon schrieb:</p>
<blockquote>
<p>In einer Messung von Thomas Krenn einer Intel-SSD im Januar (Link weiter unten) zeigte sich da kein Unterschied zwischen sequentiellen und zufälligen Zugriffen, und wenn man die 8 Terabyte Zähler da wirklich mit 90 MB/s durchdübeln kann, reden wir nur noch von einem Tag. Das alles unter dem Vorbehalt einer Messung, die ich noch tun muss -- dummerweise bedeutet das, dass diese Hochrechnung nicht so richtig wertvoll ist.</p>
</blockquote>
<p>Die 90 MB/s kommen schon hin. Mit Queue-Depth &quot;ganz viel&quot;, und 4K Zugriffen. Mit 512 Byte Zugriffen (=1 Sektor= kleiner geht nicht) schafft eine moderne SSD es auch noch (aber nur weil sie mit 4K deutlich mehr als 90 MB/s schafft).<br />
Und von den 512 Byte verwendest du worst-case dann 4 (oder 1 oder 6 oder 8 - einen Zähler halt - kommt dann drauf an ob man ne Spetialbehandlung für überlaufende Zähler machen will, oder lieben den Zähler so breit dass er nicht überlaufen kann). Und im average-case werden es auch deutlich weniger als 512 Byte sein. Mit MB/s zu rechnen führt hier nicht weit =&gt; IOPS ist schon der sinnvolle Wert beim Rausschreiben der Zähler.</p>
<p>seldon schrieb:</p>
<blockquote>
<p>Gegenrechnung Mergesort: Ich hab wieder mal gemessen. Auf meinem i7-4771 dauert ein std::sort (also ein Quicksort) von 1 GB Zufallsdaten ~21 Sekunden. Das muss man tausend mal machen, sind knapp 6 Stunden. zwei davon im RAM zu std::mergen dauert hier 0,41 Sekunden. Wenn man alles im Speicher halten könnte und durch sukzessives Mergen größere Vektoren zusammenbauen würde (immer zwei mergen), wäre man am Ende hochgerechnet eine halbe Stunde beschäftigt. Das alles im RAM zu halten ist natürlich illusorisch, wenn uns nur 2 GB zur Verfügung stehen. Nehmen wir - jetzt wird's dekadent - eine &gt;2 Terabyte-SSD als scratch space an, die einen Datendurchsatz von 250 MB/s Lesen und 90 MB/s Schreiben schafft (das sind Optimalwerte aus <a href="http://www.thomas-krenn.com/de/wiki/I/O_Performance_Vergleich_von_Festplatten_mit_SSDs_und_Fusion-io_ioDrive" rel="nofollow">einer Messung von Thomas Krenn im Januar</a>). Wir erzeugen ein Datenvolumen von 10 TB (10 Merge-Ebenen, für die jeweils der gesamte Content gelesen und geschrieben wird. Die naheliegende Idee, alles gleichzeitig zu mergen, skaliert mit O(n<sup>2</sup>) und wird langsamer sein), das macht 11 Stunden Lesen und 1 Tag und gut 6 Stunden Schreiben. Wir sind inzwischen bei 2 Tagen.</p>
<p>(jeweils plus das, was in beiden Fällen gemacht werden muss)</p>
</blockquote>
<p>#1 ich weiss nicht wo du die Werte hernimmst. Die €180 Samsung 840 PRO in meinem PC schafft an die 500 MB/s beim linear lesen und auch beim linear Schreiben.</p>
<p>#2 wieso sollte man immer nur jeweils zwei Blöcke auf einmal zusammenmergen? Damit meine Variante abstinkt?<br />
Als erstes zerteilst du das File in 1000 1 GB Blöcke, und sortierst diese (Quicksort). Soweit OK.<br />
Aber dann mergest du <em>alle 1000 Blöcke in einem Durchgang</em> zusammen.<br />
Die Daten der Input-Blöcke kannst du dabei mit einem z.B. 1 MB Puffer pro Block &quot;streamen&quot;. Also erstmal alle Puffer anfüllen, und wenn ein Puffer leer ist, liest du einen neuen 1 MB Block aus der passenden Stelle des Temp-Files.<br />
Und die Output-Daten streamst du ebenso wieder: alles in einen 1 MB (oder gerne auch etwas grösser) Output-Puffer schreiben, und wenn der voll ist ans Output-File anhängen.</p>
<p>Der IO Aufwand beim Mergen beläuft sich damit auf 1x Lesen und 1x Schreiben von jeweils 1 TB. In 1 MB Blöcken, was, wie ich früher schon erwähnt habe, so-gut-wie optimale Geschwindigkeit bedeutet. Auch mit ner HDD.</p>
<p>seldon schrieb:</p>
<blockquote>
<p>Egal, was am Ende konkret schneller wäre, man kann sich bei solchen Datenmengen nicht mehr auf sein Gefühl verlassen -- vor allem, wenn sich das Gefühl vor allem um etwas dreht, das am Ende einen konstanten Faktor ausmacht. Den Daumen vor die Schnauze zu halten und zu sagen &quot;Komplexitätsklasse, gähn. Gefühlt muss der Mergesort da in zwei Stunden durch sein&quot; führt einen in die Irre. Der Haken ist genau</p>
<p>hustbaer schrieb:</p>
<blockquote>
<p>Zumindest nicht bei gängigen Systemen mit gängigen RAM Grössen.</p>
</blockquote>
<p>...wir reden hier nicht mehr von gängigen Größen.</p>
</blockquote>
<p>Also erstmal hast du hier genau das selbe gemacht - aber OK, das schreibst du ja gleich selbst <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
<p>Und dann... wie, keine gängigen Grössen? Ich hab <em>RAM</em> Grössen geschreiben. Und 2 GB RAM ... naja, OK, das ist sogar schon weniger als &quot;gängig&quot;.<br />
Mein Einwand war konkret bezogen auf dein Abtun von Bäumen als in-memory Datenstruktur &quot;weil Komplexitätsklasse&quot;. Und da kannst du gerne mal googeln - eine Hashmap ist <em>in-memory</em> fast nie wesentlich schneller als ein Baum. Weil keiner genug RAM hat um in Bereiche vorzustossen wo die Hashmap aufholen könnte.<br />
Mit einem einfachen Hashtable, selbst implementiert, ohne double Hashing oder Buckets oder sonstwas, könnte man um eine Grössenordnung schneller sein. Den würde man dann nicht gesamt &quot;flushen&quot;, sondern einfach bei ner Kollision den einen kollidierenden Wert &quot;flushen&quot;. Was vermutlich sogar gut wäre, da die HDD/SSD dann fast permanent arbeitet und es kaum Pausen gibt wo &quot;nur gerechnet&quot; wird. Die IO Kosten bringen dich dabei aber immer noch um.</p>
<p>Und gerade um das Senken der IO Kosten ging es mir ja beim Vorschlag statt der Hashmap eine Treemap zu verwenden. Weil man die &quot;sortiert&quot; rausschreiben kann, was für ne HDD ein wesentlich günstigeres Zugriffsmuster ist als &quot;random&quot;. Auch wenn man dabei immer weder etliche Sektoren überspringt. Und selbst mit einer SSD kannst du mit der Treemap Zähler die im selben Sektor liegen mit nur einem Zugriff rausschreiben, wohingegen du mit der Hashmap diesen Sektor dann doppelt oder dreifach angreifen müsstest.</p>
<p>seldon schrieb:</p>
<blockquote>
<p>Medallien-Kehrseite: Ich hab den Effekt des log(n)-Faktors größer eingeschätzt und hätte erwartet, dass der mergesort deutlich länger braucht. Den Schuh des getrügten Gefühls muss ich mir auch anziehen.</p>
</blockquote>
<p>Hihi, genau. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>seldon schrieb:</p>
<blockquote>
<p>Worauf wir jetzt noch überhaupt nicht eingegangen sind, ist der eigentliche Trick im Umgang mit solchen Datenmassen: Parallelisierung. Ich habe in der Aufgabenstellung jetzt keine Information darüber gesehen, wie viele Prozessorkerne der TE benutzen darf, aber letztendlich ist das Szenario der Aufgabe eh unrealistisch. Ich lass mal folgenden Link da:</p>
<p><a href="http://sortbenchmark.org/" rel="nofollow">http://sortbenchmark.org/</a></p>
<p>...und stelle anheim, dass derart große Datenmengen in der Praxis immer verteilt auf großen HPC-Clustern verarbeitet werden, wo man das in brauchbarer Zeit hinkriegt, und wo jede Node auch ausreichend RAM rumliegen hat, um nicht dauernd Dinge auf Platte schreiben zu müssen. Und da sortiert man dann auch ganz sicher nicht einfach nur Zahlen, womit sich die Zählerei sowieso erledigt hat.</p>
</blockquote>
<p>Womit wir dann vermutlich wieder beim Quicksort + Merge wären, weil das supi-einfach parallelisierbar ist <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2399084</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2399084</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Wed, 14 May 2014 01:06:07 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Wed, 14 May 2014 01:32:50 GMT]]></title><description><![CDATA[<p>volkard schrieb:</p>
<blockquote>
<p>Hat man zufällig drei Drehplatten? Dann könnte man immer von zweien auf die dritte mergen und hätte stets volle Bandbreite.</p>
</blockquote>
<p>Wieso nicht erst mit Quicksort handliche Blöcke machen, und die dann alle auf einmal mergen?<br />
Oder spinne ich jetzt und Mergen ist in Wirklichkeit gar nicht streambar?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2399085</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2399085</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Wed, 14 May 2014 01:32:50 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Wed, 14 May 2014 11:16:46 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p>volkard schrieb:</p>
<blockquote>
<p>Hat man zufällig drei Drehplatten? Dann könnte man immer von zweien auf die dritte mergen und hätte stets volle Bandbreite.</p>
</blockquote>
<p>Wieso nicht erst mit Quicksort handliche Blöcke machen, und die dann alle auf einmal mergen?<br />
Oder spinne ich jetzt und Mergen ist in Wirklichkeit gar nicht streambar?</p>
</blockquote>
<p>Die 500 handlichen Dateien könnten dazu führen, daß wenn man sie auf einer Drehplatte zugleich lesen will, daß pro neuem Sektor der Kamm die volle Random-Seek-Zeit braucht (das sind Millisekunden!). Mit 3 Platten müßte der Kamm nie umherspringen, sondern nur gelegentlich mal einen Zylinder um +-1 wechseln.</p>
<p>Klar vorher Quicksort/Introsort und alle kleineren Tricks.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2399086</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2399086</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Wed, 14 May 2014 11:16:46 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Wed, 14 May 2014 07:45:58 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p>seldon schrieb:<br />
Worauf wir jetzt noch überhaupt nicht eingegangen sind, ist der eigentliche Trick im Umgang mit solchen Datenmassen: Parallelisierung. Ich habe in der Aufgabenstellung jetzt keine Information darüber gesehen, wie viele Prozessorkerne der TE benutzen darf, aber letztendlich ist das Szenario der Aufgabe eh unrealistisch. Ich lass mal folgenden Link da:</p>
<p><a href="http://sortbenchmark.org/" rel="nofollow">http://sortbenchmark.org/</a></p>
<p>...und stelle anheim, dass derart große Datenmengen in der Praxis immer verteilt auf großen HPC-Clustern verarbeitet werden, wo man das in brauchbarer Zeit hinkriegt, und wo jede Node auch ausreichend RAM rumliegen hat, um nicht dauernd Dinge auf Platte schreiben zu müssen. Und da sortiert man dann auch ganz sicher nicht einfach nur Zahlen, womit sich die Zählerei sowieso erledigt hat.</p>
<p>Womit wir dann vermutlich wieder beim Quicksort + Merge wären, weil das supi-einfach parallelisierbar ist <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
</blockquote>
<p>Wobei die Zeiten dort durch 2 &quot;Tricks&quot; entstehen:<br />
1. Die Zeiten, um die Daten im Hadoop Cluster zu verteilen, werden nicht gemessen. (MMn ist das der grosse Fake: Eigentlich gehoert das mit dazu um eine Vergleichbarkeit der Loesungsansaetze zu bekommen. Ggf. einfach als getrennte Messung, aber wenigstens dokumentiert)<br />
2. Es werden deutlich mehr Daten verarbeitet, damit ueberhaupt alle Knoten etwas sinnvolles zu tun haben.</p>
<p>Dennoch: Die von Hustbaer vorgeschlagene Loesung mit Streaming der vorher mit Quicksort sortierten Bloecke halte ich fuer den einzig sinnvollen Ansatz auf einer einzelnen Maschine. Ein Optimierungsansatz waere vielleicht KEIN RAID zu nutzen sondern nur ein BOD (Bunch of Disks) und die vorsortierten Bloecke geschickt auf die Platten (und Disk-Controller) zu verteilen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2399092</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2399092</guid><dc:creator><![CDATA[asdfaaa]]></dc:creator><pubDate>Wed, 14 May 2014 07:45:58 GMT</pubDate></item><item><title><![CDATA[Reply to Sort 1TB file on Wed, 14 May 2014 23:34:53 GMT]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/106">@volkard</a><br />
Ja, 100% Linear-Lesen Geschwindigkeit wird man nicht bekommen. (Ich hab' mich auch wiedermal verschätzt mit 1 MB Puffern ist man sogar noch deutlich davon entfernt - siehe unten.)</p>
<p>Aber wenn man den Grossteil der 2 GB RAM die man hat zum Puffern der 500~1000 Input-Streams verwendet, dann wird's schon gehen. 1 MB pro Input-Stream sollten damit locker drin sein. Wenn man die Grenzen gut auslotet (also wie viel RAM man wirklich verwenden kann, bevor das OS anfängt zu pagen) vermutlich sogar etwas mehr.</p>
<p>Laut <a href="http://www.tomshardware.com/charts/hdd-charts-2013/-07-Read-Access-Time-h2benchw-3.16,2898.html" rel="nofollow">h2benchw</a> liegen Desktop HDDs so im Bereich 12~20ms für das Lesen eines Sektors an einer zufälligen Position - nehmen wir mal 16ms an (Mittelfeld).<br />
Danach geht's mit Linear-Lesen Geschwindigkeit weiter - im Moment so ca. 130~150 MS/s -- nehmen wir 140 MB/s an.<br />
D.h. pro Megabyte ca. 7ms.<br />
In Summe für 1 MB Lesen an einer zufälligen Position dann 16+7=23ms.<br />
D.h. wir bekommen auf der HDD immer noch ~43 MB/s hin.<br />
Also ca. 1/3 von der Linear-Lesen Geschwindigkeit.</p>
<p>Die Zwischenpuffer für das Mergen von je zwei Streams zu einem kann man viel kleiner machen, da ein &quot;Seek&quot; im RAM ja kaum weh tut. 64 KB sollten da locker reichen, d.h. dafür geht kaum RAM drauf (insgesamt weniger als 100 MB).</p>
<p>Den Output-Puffer können wir grösser machen, von dem brauchen wir ja nur einen. 100 MB sollte man sich dafür leisten können. Ich nehme dafür jetzt einfach mal 100 MB/s für's Schreiben an (wird real eher mehr sein), also 10ms pro Megabyte.</p>
<p>D.h. wir brauchen für den Merge pro Megabyte insgesamt 23ms zum Lesen und 10ms zum Schreiben, also in Summe 33ms.</p>
<p>Wenn wir mehrere Durchgänge machen, so dass wir immer volle Speed bekommen, brauchen wir pro Megabyte pro Durchgang idealerweise 7 Lesen + 7 Schreiben=14ms.</p>
<p>=&gt; Wenn wir mit zwei Durchgängen auskommen, dann sind wir mit 28 statt 33 ms knapp schneller.<br />
Wenn wir mehr als zwei Durchgänge brauchen gewinnt aber schon die &quot;alles in einem&quot; Variante (deutlich). Und mit ner SSD sowieso.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2399230</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2399230</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Wed, 14 May 2014 23:34:53 GMT</pubDate></item></channel></rss>