{"id":344909,"date":"2023-02-03T09:00:38","date_gmt":"2023-02-03T09:00:38","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=344909"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=344909","title":{"rendered":"<span>\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u0435\u043c \u2014 \u043d\u0435 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e, \u043a\u0430\u043a \u043a\u0430\u0436\u0435\u0442\u0441\u044f<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043d\u0442\u043e\u0440\u0435 \u0441\u043e\u0438\u0441\u043a\u0430\u0442\u0435\u043b\u044e \u043d\u0430 \u043f\u043e\u0437\u0438\u0446\u0438\u044e Senior C# developer \u0432\u044b\u0434\u0430\u043b\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435: \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u0441\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430.<\/p>\n<p>\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0430\u043a\u0438\u0435:<\/p>\n<ul>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430\u0442 \u0441\u0442\u0440\u043e\u043a\u0438: \u0447\u0438\u0441\u043b\u043e, \u0442\u043e\u0447\u043a\u0430, \u043f\u0440\u043e\u0431\u0435\u043b, \u0434\u0430\u043b\u0435\u0435 \u043b\u044e\u0431\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u0441\u0442\u0440\u043e\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u2014 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0440\u043e\u043a\u0438, \u043f\u043e\u0442\u043e\u043c \u043f\u043e \u0447\u0438\u0441\u043b\u0443 \u0435\u0441\u043b\u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430 \u2014 UTF-8<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430 \u2014 100\u0433\u0431 &#8212; \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043e\u0431\u044a\u0435\u043c\u0430 \u041e\u041f<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u043b\u0436\u043d\u043e \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0437\u0430 1 \u0447\u0430\u0441 \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0449\u0435\u0433\u043e, \u0432\u0440\u044f\u0434 \u043b\u0438 \u0442\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u0443\u043f\u0435\u0440-\u0431\u044b\u0441\u0442\u0440\u044b\u0439 SSD \u0438 \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u0430\u043a \u0438 \u043c\u043d\u043e\u0433\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u044b, \u0443\u0437\u043d\u0430\u0432 \u043e \u0442\u0430\u043a\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0437\u0430\u0434\u0430\u043d\u0438\u0438, \u044f \u0432\u043e\u0437\u043c\u0443\u0442\u0438\u043b\u0441\u044f. \u0412\u043d\u0435\u0448\u043d\u044e\u044e \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u0441\u043b\u0438\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043b\u0438 \u0432 \u0412\u0423\u0417\u0435, \u043d\u043e \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0438\u043a\u0442\u043e \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043f\u0438\u0441\u0430\u043b \u0435\u0451. \u0417\u0430\u0434\u0430\u0447\u0430 \u043e\u0447\u0435\u043d\u044c \u043d\u0435\u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0438 \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e \u043a\u0430\u043a\u0438\u0435 \u043d\u0430\u0432\u044b\u043a\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442. \u0422\u0430\u043a \u043c\u043d\u0435 \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c.<\/p>\n<p>\u042d\u0442\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u0432\u044b\u0437\u0432\u0430\u043b\u0430 \u0431\u0443\u0440\u043d\u044b\u0435 \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u044f \u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u0445 \u0435\u0451 \u0440\u0435\u0448\u0435\u043d\u0438\u044f. \u041c\u043d\u043e\u0433\u0438\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u044b, \u043f\u0440\u0438\u0447\u0438\u0441\u043b\u044f\u044e\u0449\u0438\u0435 \u0441\u0435\u0431\u044f \u043a \u0440\u0430\u043d\u0433\u0443 senior, \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0438\u0431\u043e \u043d\u0435 \u0431\u0430\u0440\u0441\u043a\u043e\u0435 \u044d\u0442\u043e \u0434\u0435\u043b\u043e &#8212; \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0438\u0441\u0430\u0442\u044c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0430\u0436\u0435 \u043f\u043e\u043f\u044b\u0442\u0430\u043b\u0438\u0441\u044c  \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 Apache Spark. \u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0438\u043a\u0442\u043e \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u0437\u0430\u0434\u0430\u0447\u0443 \u043d\u0435 \u0440\u0435\u0448\u0438\u043b, \u0438\u0431\u043e \u043c\u0430\u043b\u043e \u043a\u043e\u043c\u0443 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u0434\u0430\u0436\u0435 10\u0413\u0411 \u0444\u0430\u0439\u043b \u043c\u0435\u043d\u0435\u0435 \u0447\u0435\u043c \u0437\u0430 15 \u043c\u0438\u043d\u0443\u0442 \u0431\u0435\u0437 SSD.<\/p>\n<p>\u042f \u043f\u043e\u0434\u0443\u043c\u0430\u043b, \u0447\u0442\u043e \u0441\u0442\u043e\u0438\u0442 \u0440\u0435\u0448\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443 \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0438 \u0442\u043e\u0436\u0435 \u043f\u0440\u0438\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0441\u0435\u0431\u044f \u043a \u0440\u0430\u043d\u0433\u0443 senior developer.<\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043d\u0443\u0436\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0437\u044f\u043b \u043f\u0435\u0440\u0432\u044b\u0439 \u0442\u043e\u043c \u0412\u043e\u0439\u043d\u044b \u0438 \u041c\u0438\u0440\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u043a\u0430\u043a \u0440\u0443\u0441\u0441\u043a\u0438\u0435, \u0442\u0430\u043a \u0438 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b.  <\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">var source = (from l in File.ReadLines(\"source.txt\")               where !string.IsNullOrEmpty(l)               from s in l.Split(new[] { '.', '?', '!', '[', ']' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)               where s.Length > 10               select s).ToList();  Random rand = new();  using (var f = File.CreateText(file)) {     f.AutoFlush = false;     while(f.BaseStream.Position &lt; maxSize)     {         var n = rand.Next();         f.Write(n);         f.Write(\". \");         f.WriteLine(source[rand.Next(source.Count)]);     } } return 0;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0435\u0448\u0438\u043b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c 10\u0413\u0411, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0436\u0434\u0430\u0442\u044c \u0447\u0430\u0441 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u043f\u0440\u043e\u0433\u043e\u043d\u0435. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b \u0442\u0430\u043a\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043d\u0435 \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u044d\u0448\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0447\u0442\u0435\u043d\u0438\u044f-\u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u043e\u0445\u043e\u0434\u044f\u0442 \u0434\u043e \u0434\u0438\u0441\u043a\u0430, \u0447\u0442\u043e \u0434\u0430\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0431\u044b\u0441\u0442\u0440\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043e\u0431\u044a\u0435\u043c\u0430\u0445.<\/p>\n<h2>\u0421\u0430\u043c\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412\u0441\u0435 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441\u043e <a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/712234\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430 \u0445\u0430\u0431\u0440\u0435 \u043e \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0435<\/a>. \u0421\u0440\u0430\u0437\u0443 \u043e\u0442\u0431\u0440\u043e\u0441\u0438\u043b \u0438\u0434\u0435\u044e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432 \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0431\u043b\u043e\u043a\u043e\u0432, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u043b\u043e \u0431\u044b \u043a \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0437\u0430\u0442\u0440\u0430\u0442\u0430\u043c \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c. \u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043b \u043d\u0430 \u0434\u0432\u0435 \u0444\u0430\u0437\u044b \u2014 <em>\u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435<\/em> \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 (<em>\u0447\u0430\u043d\u043a\u0438<\/em>, \u043e\u0442 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u0433\u043e <em>chunk<\/em>) \u0438 <em>\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430<\/em> \u0441\u0442\u0440\u043e\u043a \u0432 \u0431\u043b\u043e\u043a\u0430\u0445, <em>\u0441\u043b\u0438\u044f\u043d\u0438\u0435<\/em> \u0431\u043b\u043e\u043a\u043e\u0432 \u0432 \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b.<\/p>\n<p>\u041a\u043e\u0434 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f<\/p>\n<pre><code class=\"cs\">var count = 0; var tempFiles =     File.ReadLines(file)         .Select(s => new Item(s, s.IndexOf('.')))         .Chunk(chunkSize)         .Select(chunk =>         {             Array.Sort(chunk, comparer);             var tempFileName = Path.ChangeExtension(file, $\".part-{count++}\" + Path.GetExtension(file));             File.WriteAllLines(tempFileName, chunk.Select(x => x.Line));             return tempFileName;         }).ToList();<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u0441\u043b\u0438\u044f\u043d\u0438\u044f<\/p>\n<pre><code class=\"cs\">try {     var mergedLines = tempFiles         .Select(f => File.ReadLines(f).Select(s => new Item(s, s.IndexOf('.'))))         .Merge(comparer) \/\/ IEnumerable&lt;IEnumerable&lt;T>> -> IEnumerable&lt;T>         .Select(x => x.Line);     File.WriteAllLines(Path.ChangeExtension(file, \".sorted\" + Path.GetExtension(file)), mergedLines); } finally {     tempFiles.ForEach(File.Delete); }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u0442\u0438\u043f, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0442\u043e\u0447\u043a\u0438 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u0438 \u043a\u043e\u043c\u043f\u0430\u0440\u0430\u0442\u043e\u0440 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430<\/p>\n<pre><code class=\"cs\">public record struct Item(string Line, int DotPosition); public record Comparer(StringComparison StringComparison) : IComparer&lt;Item> {     public int Compare(Item x, Item y)     {         var spanX = x.Line.AsSpan();         var spanY = y.Line.AsSpan();         var xDot = x.DotPosition;         var yDot = y.DotPosition;          var cmp = spanX[(xDot + 2)..].CompareTo(spanY[(yDot + 2)..], StringComparison);         if (cmp != 0) return cmp;         return int.Parse(spanX[..xDot]) - int.Parse(spanY[..yDot]);     } }<\/code><\/pre>\n<p> &#171;\u0421\u0435\u0440\u0434\u0446\u0435&#187; \u0432\u0441\u0435\u0433\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 &#8212; \u0441\u043b\u0438\u044f\u043d\u0438\u0435 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 <\/p>\n<pre><code class=\"cs\">public static IEnumerable&lt;T> Merge&lt;T>(this IEnumerable&lt;IEnumerable&lt;T>> sources, IComparer&lt;T> comparer = default) {     var enumerators = (from source in sources                         let e = source.GetEnumerator()                         where e.MoveNext()                         select e).ToList();                  while (enumerators.Count > 0)     {         var min = enumerators.MinBy(e => e.Current, comparer)!;         yield return min.Current;         if (!min.MoveNext())         {             min.Dispose();             enumerators.Remove(min);         }     } }<\/code><\/pre>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u044f \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b async\\await? \u0412\u0435\u0434\u044c \u0441\u0435\u0439\u0447\u0430\u0441 \u0432\u0441\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u044b C# \u0432\u0442\u044b\u043a\u0430\u044e\u0442 <strong>async<\/strong>\\<strong>await<\/strong> \u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0435. \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u044f \u0442\u043e\u0436\u0435 \u0442\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u043b \u0441\u043d\u0430\u0447\u0430\u043b\u0430, \u043d\u043e \u043f\u043e\u0442\u043e\u043c \u0443\u0431\u0440\u0430\u043b.<\/p>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445 \u0434\u043b\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c Merge. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445 \u043a\u043e\u0434 \u0441 <strong>async<\/strong>\\<strong>await <\/strong>\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u043b. <strong>async<\/strong>\\<strong>await<\/strong> \u043d\u0435\u0441\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0440\u0430\u0441\u0445\u043e\u0434\u044b \u043d\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 \u0432\u0441\u044e \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u0433\u043e\u0434\u043d\u043e \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0440\u0430\u0441\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0442\u044c <em>\u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435<\/em>, \u043d\u043e \u0432 \u044d\u0442\u043e\u043c \u043a\u043e\u0434\u0435 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0439 \u043d\u0435\u0442. \u0412\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<h2>\u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a<\/h2>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u0441\u043b\u0438\u044f\u043d\u0438\u0435\u043c, \u0440\u0430\u0437\u043c\u0435\u0440 \u0447\u0430\u043d\u043a\u0430 &#8212; 1\u041c \u0441\u0442\u0440\u043e\u043a \u0438\u043b\u0438 \u043e\u043a\u043e\u043b\u043e 157\u041c\u0431, \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b &#8212; 15:30, \u043f\u044f\u0442\u043d\u0430\u0434\u0446\u0430\u0442\u044c \u0441 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u043e\u0439 \u043c\u0438\u043d\u0443\u0442! \u0412 \u0447\u0430\u0441 \u0434\u043b\u044f 100\u0413\u0431 \u0443\u043b\u043e\u0436\u0438\u0442\u044c\u0441\u044f \u043d\u0435 \u0432\u044b\u0439\u0434\u0435\u0442.<\/p>\n<p>\u0427\u0442\u043e \u043f\u043e \u0432\u0430\u0448\u0435\u043c\u0443 \u0442\u043e\u0440\u043c\u043e\u0437\u0438\u043b\u043e \u0432 \u044d\u0442\u043e\u043c \u043a\u043e\u0434\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e? \u041d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0441\u0432\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0441\u043f\u043e\u0439\u043b\u0435\u0440 \u0438 \u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u0422\u0430\u0439\u043c\u0438\u043d\u0433<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>SplitSort done in 00:04:59.2942000 Merge done in 00:10:32.1238153<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u0437\u0430\u0434\u0430\u0447 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b, \u0447\u0442\u043e \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430 \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u043c\u0430\u043b\u043e<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/006\/f75\/a40\/006f75a40c510c6db95e041a121cf87a.png\" alt=\"\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0432 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f (\u0426\u041f7 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b \u043a\u043e\u0434)\" title=\"\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0432 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f (\u0426\u041f7 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b \u043a\u043e\u0434)\" width=\"1894\" height=\"891\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/006\/f75\/a40\/006f75a40c510c6db95e041a121cf87a.png\"\/><figcaption>\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0432 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f (\u0426\u041f7 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b \u043a\u043e\u0434)<\/figcaption><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cc4\/4a8\/e6d\/cc44a8e6d9f6234a913c04fcef1c4dc8.png\" alt=\"\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u0434\u0438\u0441\u043a \u0432 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f\" title=\"\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u0434\u0438\u0441\u043a \u0432 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f\" width=\"1894\" height=\"891\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/cc4\/4a8\/e6d\/cc44a8e6d9f6234a913c04fcef1c4dc8.png\"\/><figcaption>\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u0434\u0438\u0441\u043a \u0432 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f<\/figcaption><\/figure>\n<p>\u041a\u043e\u0434 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 <a href=\"https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/naive\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/naive<\/a><\/p>\n<h2>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0441\u043b\u0438\u044f\u043d\u0438\u0435<\/h2>\n<p>\u0414\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0435 \u0447\u0442\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c, \u0430 \u043f\u043e\u0438\u0441\u043a \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043b\u0438\u044f\u043d\u0438\u044f. \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u044f \u0447\u0435\u0441\u0442\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0430\u043c, \u043d\u0435 \u043f\u043e\u0434\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044f \u0432 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f. \u0413\u043e\u0440\u0430\u0437\u0434\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0430\u00a0\u0434\u0430\u043b\u0435\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0438\u0445 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 <em>.MoveNext()<\/em>, \u0434\u0430\u0436\u0435 <a href=\"https:\/\/stackoverflow.com\/questions\/2767007\/most-efficient-algorithm-for-merging-sorted-ienumerablet\" rel=\"noopener noreferrer nofollow\">\u043d\u0430 StackOverflow<\/a> \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442 \u0442\u0430\u043a\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442.<\/p>\n<p>\u041b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442 <a href=\"https:\/\/habr.com\/ru\/post\/112222\/\" rel=\"noopener noreferrer nofollow\">\u0434\u0432\u043e\u0438\u0447\u043d\u0430\u044f (\u043e\u043d\u0430 \u0436\u0435 \u0431\u0438\u043d\u0430\u0440\u043d\u0430\u044f) \u043a\u0443\u0447\u0430<\/a>. \u041e\u043d\u0430 \u0438\u043c\u0435\u0435\u0442 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u043a\u043e\u0440\u043d\u0435 \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u0437\u0430 O(logN), \u0433\u0434\u0435 K &#8212; \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u043a\u0443\u0447\u0435 (\u0443 \u043d\u0430\u0441 \u0440\u0430\u0432\u043d\u043e \u0447\u0438\u0441\u043b\u0443 \u0447\u0430\u043d\u043a\u043e\u0432). \u0415\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u044f \u043d\u0435 \u0441\u0430\u043c \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u043b, \u0430 \u043f\u043e\u0434\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u041c\u0435\u0442\u043e\u0434\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u0443\u0447\u0435\u0439<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">public static void Heapify&lt;T>(this Span&lt;T> heap, int index, IComparer&lt;T> comparer) {     ArgumentNullException.ThrowIfNull(comparer);      var min = index;     while (true)     {         var leftChild = 2 * index + 1;         var rightChild = 2 * index + 2;         var v = heap[index];          if (rightChild &lt; heap.Length &amp;&amp; comparer.Compare(v, heap[rightChild]) > 0)         {             min = rightChild;             v = heap[min];         }          if (leftChild &lt; heap.Length &amp;&amp; comparer.Compare(v, heap[leftChild]) > 0)         {             min = leftChild;         }          if (min == index) break;          var temp = heap[index];         heap[index] = heap[min];         heap[min] = temp;          index = min;     } }  public static void BuildHeap&lt;T>(this Span&lt;T> heap, IComparer&lt;T> comparer) {     ArgumentNullException.ThrowIfNull(comparer);      for (int i = heap.Length \/ 2; i >= 0; i--)     {         Heapify(heap, i, comparer);     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041a\u043e\u0434 \u043c\u0435\u0442\u043e\u0434\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u044f<\/p>\n<pre><code class=\"cs\">public static IEnumerable&lt;T> Merge&lt;T>(this IEnumerable&lt;IEnumerable&lt;T>> sources, IComparer&lt;T> comparer = default) {     var heap = (from source in sources                 let e = source.GetEnumerator()                 where e.MoveNext()                 select e).ToArray();      var enumeratorComparer = new EnumeratorComparer&lt;T>(comparer ?? Comparer&lt;T>.Default);     heap.AsSpan().BuildHeap(enumeratorComparer);      while (true)     {         var min = heap[0];         yield return min.Current;         if (!min.MoveNext())         {             min.Dispose();             if (heap.Length == 1) yield break;             heap[0] = heap[^1];             Array.Resize(ref heap, heap.Length - 1);         }         heap.AsSpan().Heapify(0, enumeratorComparer);     } }  private record EnumeratorComparer&lt;T>(IComparer&lt;T> comparer) : IComparer&lt;IEnumerator&lt;T>> {     public int Compare(IEnumerator&lt;T>? x, IEnumerator&lt;T>? y)     {         return comparer.Compare(x!.Current, y!.Current);     } }<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u0434 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f. \u0412\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b:<\/p>\n<pre><code>SplitSort done in 00:04:27.8391844 Merge done in 00:02:11.4364005<\/code><\/pre>\n<p>\u0417\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043b\u0443\u0447\u0448\u0435, \u043d\u043e \u0434\u043e \u0437\u0430\u0432\u0435\u0442\u043d\u043e\u0433\u043e \u0447\u0430\u0441\u0430 \u043d\u0430 100\u0413\u0411 \u0435\u0449\u0435 \u043e\u0447\u0435\u043d\u044c \u0434\u0430\u043b\u0435\u043a\u043e. \u0422\u0443\u0442 \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0438\u0437-\u0437\u0430 \u043a\u044d\u0448\u0430 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u0440\u044c\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f +\\-15%<\/p>\n<p>\u041a\u043e\u0434 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 <a href=\"https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/heapsort\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/heapsort<\/a><\/p>\n<h3>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0424\u0430\u0437\u044b \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f \u0438 \u0441\u043b\u0438\u044f\u043d\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0447\u0442\u0435\u043d\u0438\u044f-\u0437\u0430\u043f\u0438\u0441\u0438, \u0441\u043e\u0437\u0434\u0430\u044e\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0442\u0438\u043f\u0430 string, \u043d\u043e \u0444\u0430\u0437\u0430 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0432 2,5 \u0440\u0430\u0437 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u0430\u043c\u044f\u0442\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u043e\u0434 \u043e\u0442\u043b\u0430\u0434\u0447\u0438\u043a\u043e\u043c \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0441\u0431\u043e\u0440\u043e\u043a \u043c\u0443\u0441\u043e\u0440\u0430.<\/p>\n<p>\u0412\u0441\u0435 \u0434\u0435\u043b\u043e <strong>\u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0436\u0438\u0437\u043d\u0438<\/strong> \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432. \u0412 \u0444\u0430\u0437\u0435 \u0441\u043b\u0438\u044f\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0436\u0438\u0432\u0435\u0442 \u043e\u0442 \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u0447\u0430\u043d\u043a\u0430 \u0434\u043e \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0444\u0430\u0439\u043b. \u041a\u043e\u0433\u0434\u0430 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0438\u0437 \u0447\u0430\u043d\u043a\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u0443\u0436\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043b\u0430\u0441\u044c \u043c\u0443\u0441\u043e\u0440. \u041c\u0443\u0441\u043e\u0440 \u0443\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0432 \u043d\u0443\u043b\u0435\u0432\u043e\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438 \u0441\u0431\u043e\u0440\u0449\u0438\u043a\u0430, \u044d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u043f\u0430\u043c\u044f\u0442\u044c \u043d\u0435 \u0440\u0430\u0441\u0442\u0435\u0442.<\/p>\n<p>\u0412 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0441\u0442\u0440\u043e\u043a \u0436\u0438\u0432\u0443\u0442 \u043e\u0442 \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0434\u043e \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0447\u0430\u043d\u043a. \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441\u0442\u0440\u043e\u043a \u043f\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0431\u043e\u0440\u043e\u043a \u043c\u0443\u0441\u043e\u0440\u0430, \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u043d\u0443\u044e \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0441\u0431\u043e\u0440\u0449\u0438\u043a\u0430 \u0438 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u0435\u043c\u0443\u044e \u043f\u0430\u043c\u044f\u0442\u044c.<\/p>\n<p>\u041c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438 \u0441\u0442\u0440\u043e\u043a \u043d\u0430 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f. \u041d\u043e \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c! \u041c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \u0431\u043b\u043e\u043a \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e \u0441\u0438\u043c\u0432\u043e\u043b\u0443 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0442\u0440\u043e\u043a \u0442\u0438\u043f <code>ReadOnlyMemory&lt;char><\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0443 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c. <code>ReadOnlyMemory&lt;char><\/code> \u044d\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 (\u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0430\u043b\u043b\u043e\u043a\u0430\u0446\u0438\u0439 \u0432 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0439 \u043a\u0443\u0447\u0435), \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043c\u0430\u0441\u0441\u0438\u0432, \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0438 \u0434\u043b\u0438\u043d\u0443.<\/p>\n<p>\u041a\u043e\u0434 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f \u0431\u0435\u0437 \u0430\u043b\u043b\u043e\u043a\u0430\u0446\u0438\u0439<\/p>\n<pre><code class=\"cs\">List&lt;string> tempFiles = new(); List&lt;Item> chunk = new(); using (var reader = File.OpenText(file)) {     var chunkBuffer = new char[chunkSize];     var chunkReadPosition = 0;     var eos = reader.EndOfStream;     while (!eos)     {         \/\/ \u0427\u0438\u0442\u0430\u0435\u043c \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \u0432\u0435\u0441\u044c \u0431\u0443\u0444\u0435\u0440         var charsRead = reader.ReadBlock(chunkBuffer.AsSpan(chunkReadPosition));         eos = reader.EndOfStream;         var m = chunkBuffer.AsMemory(0, chunkReadPosition + charsRead);          \/\/ \u0417\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0440\u043e\u043a ReadOnlyMemory&lt;char> \u0434\u043b\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438         int linePos;         while ((linePos = m.Span.IndexOf(Environment.NewLine)) >= 0 || (eos &amp;&amp; m.Length > 0))         {             var line = linePos >= 0 ? m[..linePos] : m;             chunk.Add(new Item(line, line.Span.IndexOf('.')));             m = m[(linePos + Environment.NewLine.Length)..];         }          chunk.Sort(comparer);          \/\/ \u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b         var tempFileName = Path.ChangeExtension(file, $\".part-{tempFiles.Count}\" + Path.GetExtension(file));         using (var tempFile = File.CreateText(tempFileName))         {             foreach (var (l, _) in chunk)             {                 tempFile.WriteLine(l);             }         }         tempFiles.Add(tempFileName);          if (eos) break;         chunk.Clear();          \/\/\u041e\u0442\u0441\u0442\u043e\u043a \u0431\u0443\u0444\u0435\u0440\u0430 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u043c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e         m.CopyTo(chunkBuffer);         chunkReadPosition = m.Length;     } }<\/code><\/pre>\n<p>\u041c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u0434 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435, \u043d\u043e \u0442\u043e\u0433\u0434\u0430 \u043a\u043e\u0434 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0431\u044b \u0431\u043e\u043b\u0435\u0435 \u043d\u0435\u0443\u043a\u043b\u044e\u0436\u0438\u043c \u0438\u0437-\u0437\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0444\u043b\u0430\u0433\u0430 \u043a\u043e\u043d\u0446\u0430 \u0444\u0430\u0439\u043b\u0430.<\/p>\n<p>\u0412 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043c\u0435\u043d\u0438\u043b <code>string<\/code> \u043d\u0430<code>ReadOnlyMemory&lt;char><\/code>\u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c.<\/p>\n<p>\u0412\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u0435 \u0447\u0430\u043d\u043a\u0430 \u0432 100\u041c <em>\u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432<\/em>, 161\u041c\u0431 \u043d\u0430 \u0434\u0438\u0441\u043a\u0435:<\/p>\n<pre><code>SplitSort done in 00:03:50.6780519 Merge done in 00:02:19.5627238<\/code><\/pre>\n<p>\u0423\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u044b\u0438\u0433\u0440\u0430\u0442\u044c \u0435\u0449\u0435 30 \u0441\u0435\u043a \u0438 \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0440\u0430\u0441\u0445\u043e\u0434 \u043f\u0430\u043c\u044f\u0442\u0438 \u043d\u0430 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f \u0441\u043e 600 \u0434\u043e 250 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442. \u041a\u0430\u043a \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f Allocation is cheap\u2026 until it is not (<a href=\"https:\/\/tooslowexception.com\/allocation-is-cheap-until-it-is-not\/\" rel=\"noopener noreferrer nofollow\">https:\/\/tooslowexception.com\/allocation-is-cheap-until-it-is-not\/<\/a> \u0441\u0442\u0430\u0442\u044c\u044f \u043e\u0442 \u0434\u0440\u0443\u0433\u043e\u043c, \u043d\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442).<\/p>\n<p>\u041a\u043e\u0434 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 <a href=\"https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/reduced-allocations\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/reduced-allocations<\/a><\/p>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e \u043d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0447\u0438\u043b\u0438\u0441\u044c, \u0430 \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u0441\u0435 \u0435\u0449\u0435 \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0443\u043b\u043e\u0436\u0438\u0442\u044c\u0441\u044f \u0432 \u0447\u0430\u0441.<\/p>\n<h2>\u041a\u0430\u043a \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438<\/h2>\n<p>\u0414\u043b\u044f \u043c\u043d\u043e\u0433\u0438\u0445 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u043e\u0432 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u043e\u043a \u044d\u0442\u043e \u0432\u0441\u0435 \u0435\u0449\u0435 \u043f\u043e\u0441\u0438\u043c\u0432\u043e\u043b\u044c\u043d\u043e\u0435, \u0430 \u0434\u043b\u044f \u0442\u0435\u0445 \u043a\u0442\u043e \u043f\u0440\u0438\u0448\u0435\u043b \u0438\u0437  \u0421 \u2014 \u043f\u043e\u0431\u0430\u0439\u0442\u043d\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435. \u041d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441 2000 \u0433\u043e\u0434\u0430 \u0432\u0441\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u044e\u043d\u0438\u043a\u043e\u0434. \u042e\u043d\u0438\u043a\u043e\u0434 \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u0432\u0430 \u0431\u0430\u0439\u0442\u0430 \u043d\u0430 \u0441\u0438\u043c\u0432\u043e\u043b \u0438 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0434\u043b\u0438\u043d\u044b, \u0432\u0440\u043e\u0434\u0435 UTF8, \u044d\u0442\u043e \u0435\u0449\u0435  \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f, \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432. \u041a\u0442\u043e \u0435\u0449\u0435 \u043d\u0435 \u0432 \u043a\u0443\u0440\u0441\u0435 &#8212; \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 <a href=\"https:\/\/youtu.be\/_mZBa3sqTrI\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u043b\u0430\u0434 Plain Text<\/a> \u0414\u0438\u043b\u0430\u043d\u0430 \u0411\u0438\u0442\u0442\u0438 \u043d\u0430 NDC. \u042d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u043b\u0443\u0447\u0448\u0438\u0445 \u0434\u043e\u043a\u043b\u0430\u0434\u043e\u0432 \u0437\u0430 \u0432\u0441\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0439.<\/p>\n<p>\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u044e\u043d\u0438\u043a\u043e\u0434\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0435 <a href=\"https:\/\/unicode.org\/reports\/tr10\/\" rel=\"noopener noreferrer nofollow\">Unicode Collation Algorithm<\/a> (UCA). \u042d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432\u0435\u0441\u043e\u0432 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u043c \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u043a\u0443\u043b\u044c\u0442\u0443\u0440. \u042d\u0442\u043e\u0442 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u0432 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 (<a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/stringapiset\/nf-stringapiset-comparestringw\" rel=\"noopener noreferrer nofollow\">CompareStringW<\/a>, <a href=\"https:\/\/source.dot.net\/System.Private.CoreLib\/src\/libraries\/Common\/src\/Interop\/Windows\/Kernel32\/Interop.Globalization.cs.html#b6bbac7b6a9c27f8\" rel=\"noopener noreferrer nofollow\">CompareStringEx<\/a> \u0432 Windows \u0438 <code>CompareString<\/code> \u0438\u0437 <code>libSystem.Globalization.Native.so<\/code> \u0432 Linux).<\/p>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u0432\u0441\u0435\u0433\u043e \u043e\u0442\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e\u0441\u0438\u043c\u0432\u043e\u043b\u044c\u043d\u043e, \u044d\u0442\u043e \u0443\u0441\u043a\u043e\u0440\u0438\u0442 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u043f\u043e\u0447\u0442\u0438 \u043d\u0430 \u043c\u0438\u043d\u0443\u0442\u0443, \u0442\u0430\u043a \u043a\u0430\u043a .NET \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 API \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e. \u0414\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c <code>StringComparison.Ordinal<\/code> \u0432 <code>Comparer<\/code>. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043e\u0442\u043a\u0430\u0437 \u043e\u0442 UCA \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0440\u0430\u0437\u0440\u044f\u0434\u043d\u044b\u0435 (radix) \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043e\u0431\u044b\u0447\u043d\u044b\u0445. \u041d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0438 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043f\u043e\u0434 \u043e\u0434\u0438\u043d \u0447\u0430\u0441\u0442\u043d\u044b\u0439 \u0441\u043b\u0443\u0447\u0430\u0439. \u041d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a  UCA \u0431\u0435\u0437 \u043f\u043e\u0442\u0435\u0440\u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f.<\/p>\n<p>\u041e\u0434\u0438\u043d \u0438\u0437 \u0448\u0430\u0433\u043e\u0432 UCA \u2014 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 (sort key) \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a \u2014 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0431\u0430\u0439\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u043e\u0431\u0430\u0439\u0442\u043d\u043e\u0433\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f. \u041e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 .NET \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043b\u044e\u0447\u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0441\u0442\u0440\u043e\u043a <a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/api\/system.globalization.compareinfo.getsortkey\" rel=\"noopener noreferrer nofollow\">CompareInfo.GetSortKey<\/a>.  \u0422\u043e \u0435\u0441\u0442\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u044d\u0442\u0438 \u0431\u0430\u0439\u0442\u044b \u0438 \u043f\u043e\u0442\u043e\u043c \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0438\u0445. \u0415\u0441\u043b\u0438 \u0434\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043a\u043e\u043d\u0435\u0446 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0431\u0430\u0439\u0442\u044b \u0447\u0438\u0441\u043b\u0430, \u0441\u0442\u043e\u044f\u0449\u0435\u0433\u043e \u0432 \u043d\u0430\u0447\u0430\u043b\u0435, \u0442\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u0441\u044e \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u0441\u0432\u0435\u0441\u0442\u0438 \u043a \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0435 \u0431\u0430\u0439\u0442\u043e\u0432\u044b\u0445 \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432.<\/p>\n<p>\u0421\u043a\u043e\u0440\u043e 15\u00a0\u043b\u0435\u0442 \u043a\u0430\u043a\u00a0\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u0443\u044e \u043d\u0430 .NET \u0438 \u044f \u0443\u0437\u043d\u0430\u043b \u043e\u00a0\u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u043a\u043b\u044e\u0447\u0435\u0439 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0441\u0442\u0440\u043e\u043a \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0433\u0434\u0430 \u0440\u0435\u0448\u0430\u043b \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443.<\/p>\n<h2>\u041f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0435\u0439 \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u043f\u043e \u043d\u0438\u043c \u0432 \u043c\u0435\u0442\u043e\u0434\u044b \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f \u0438 \u0441\u043b\u0438\u044f\u043d\u0438\u044f<\/p>\n<pre><code class=\"cs\">List&lt;string> tempFiles = new(); List&lt;Item> chunk = new(); using (var reader = File.OpenText(file)) {     var keyBuffer = new byte[chunkSize * 2]; \/\/\u0411\u0443\u0444\u0435\u0440 \u0434\u043b\u044f \u043a\u043b\u044e\u0447\u0435\u0439     var chunkBuffer = new char[chunkSize];     var chunkReadPosition = 0;     var eos = reader.EndOfStream;     while (!eos)     {         \/\/ \u0427\u0438\u0442\u0430\u0435\u043c \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \u0432\u0435\u0441\u044c \u0431\u0443\u0444\u0435\u0440         var charsRead = reader.ReadBlock(chunkBuffer.AsSpan(chunkReadPosition));         eos = reader.EndOfStream;         var m = chunkBuffer.AsMemory(0, chunkReadPosition + charsRead);         var key = keyBuffer.AsMemory();          \/\/ \u0417\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0440\u043e\u043a ReadOnlyMemory&lt;char> \u0434\u043b\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438         int linePos;         while ((linePos = m.Span.IndexOf(Environment.NewLine)) >= 0 || (eos &amp;&amp; m.Length > 0))         {             var line = linePos >= 0 ? m[..linePos] : m;             var s = line.Span;             var dot = line.Span.IndexOf('.');             int x = int.Parse(s[..dot]);             s = s[(dot + 2)..];             var keyLen = culture.CompareInfo.GetSortKey(s, key.Span);    \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u043b\u044e\u0447             BinaryPrimitives.WriteInt32BigEndian(key[keyLen..].Span, x); \/\/ \u0414\u043e\u0431\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0447\u0438\u0441\u043b\u043e \u0432 \u043a\u043e\u043d\u0435\u0446 \u043a\u043b\u044e\u0447\u0430, \u0447\u0442\u043e\u0431\u044b \u0441\u0442\u0430\u0440\u0448\u044b\u0439 \u0431\u0430\u0439\u0442 \u0431\u044b\u043b \u0441 \u043c\u0435\u043d\u044c\u0448\u0438\u043c \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u043c             keyLen += sizeof(int);              chunk.Add(new Item(line, key[..keyLen]));             m = m[(linePos + Environment.NewLine.Length)..];             key = key[keyLen..];         }          chunk.Sort(comparer);          \/\/ \u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b         var tempFileName = Path.ChangeExtension(file, $\".part-{tempFiles.Count}\" + Path.GetExtension(file));         using (var tempFile = File.CreateText(tempFileName))         {             foreach (var (l, _) in chunk)             {                 tempFile.WriteLine(l);             }         }         tempFiles.Add(tempFileName);          if (eos) break;         chunk.Clear();          \/\/\u041e\u0441\u0442\u0430\u0442\u043e\u043a \u0431\u0443\u0444\u0435\u0440\u0430 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u043c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e         m.CopyTo(chunkBuffer);         chunkReadPosition = m.Length;     } }<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0441\u043b\u0438\u044f\u043d\u0438\u0438 \u043d\u0430\u043c \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0434\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043a\u043b\u044e\u0447\u0438<\/p>\n<pre><code class=\"cs\">try {     var mergedLines = tempFiles         .Select(f => File.ReadLines(f).Select(s => \/\/ \u0427\u0438\u0442\u0430\u0435\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u043e \u0432\u0441\u0435 \u0444\u0430\u0439\u043b\u044b          {             var m = s.AsMemory();             var dot = s.IndexOf('.');              \/\/ \u041d\u0430\u0445\u043e\u0434\u0438\u043c \u0432 \u0441\u0442\u0440\u043e\u043a\u0430\u0445 \u0442\u043e\u0447\u043a\u0443             int x = int.Parse(s.AsSpan(0, dot));              \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u043b\u044e\u0447 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0447\u043a\u0438 \u0441 \u043f\u0440\u043e\u0431\u0435\u043b\u043e\u043c             var key = new byte[s.Length * 2 + sizeof(int)];             var keyLen = culture.CompareInfo.GetSortKey(m[(dot + 2)..].Span, key);                           \/\/ \u0414\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0447\u0438\u0441\u043b\u043e \u0432 \u043a\u043e\u043d\u0435\u0446             BinaryPrimitives.WriteInt32BigEndian(key.AsSpan(keyLen), x);                      return new Item(m, key);         }))         .Merge(comparer);  \/\/\u0421\u043b\u0438\u044f\u043d\u0438\u0435 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 IEnumerable&lt;IEnumerable&lt;T>> \u0432 IEnumerable&lt;T>        using var sortedFile = File.CreateText(Path.ChangeExtension(file, \".sorted\" + Path.GetExtension(file)));     foreach (var (l, _) in mergedLines)     {         sortedFile.WriteLine(l);     } } finally {     tempFiles.ForEach(File.Delete); }<\/code><\/pre>\n<p>\u041a\u043e\u043c\u043f\u0430\u0440\u0430\u0442\u043e\u0440 \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439<\/p>\n<pre><code class=\"cs\">public record struct Item(ReadOnlyMemory&lt;char> Line, ReadOnlyMemory&lt;byte> Key); public class Comparer : IComparer&lt;Item> {     public int Compare(Item x, Item y)     {         return x.Key.Span.SequenceCompareTo(y.Key.Span);     } }<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e \u0445\u0443\u0436\u0435<\/p>\n<pre><code>SplitSort done in 00:04:09.5091207 Merge done in 00:03:02.5646277<\/code><\/pre>\n<p>\u041c\u044b \u043f\u0440\u043e\u0438\u0433\u0440\u0430\u043b\u0438 40 \u0441\u0435\u043a\u0443\u043d\u0434 \u043d\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u0438 \u0438\u0437-\u0437\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043b\u044e\u0447\u0435\u0439 \u0438 10 \u0441\u0435\u043a\u0443\u043d\u0434 \u043d\u0430 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0438 \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0435. \u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u043a\u043b\u044e\u0447\u0435\u0439 \u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435, \u0447\u0435\u043c \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u0441\u0442\u0440\u043e\u043a, \u043d\u043e \u043d\u0430\u043a\u043b\u0430\u0434\u043d\u044b\u0435 \u0440\u0430\u0441\u0445\u043e\u0434\u044b \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0435\u0439 \u0443\u0431\u0438\u043b\u0438 \u0432\u0435\u0441\u044c \u0432\u044b\u0438\u0433\u0440\u044b\u0448. <\/p>\n<p>\u0417\u0430\u0442\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u043e\u0440\u0430\u0437\u0440\u044f\u0434\u043d\u0443\u044e (Radix) \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u043a\u043b\u044e\u0447\u0435\u0439. \u042f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043f\u043e\u0440\u0430\u0437\u0440\u044f\u0434\u043d\u043e\u0439 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 &#8212; <a href=\"https:\/\/en.wikipedia.org\/wiki\/Multi-key_quicksort\" rel=\"noopener noreferrer nofollow\">Radix Quick Sort aka Multi-key QuickSort<\/a> (\u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0432\u0435\u043b \u043d\u0430 C# <a href=\"http:\/\/akira.ruc.dk\/~keld\/teaching\/algoritmedesign_f04\/Artikler\/04\/Bentley99.pdf\" rel=\"noopener noreferrer nofollow\">\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435<\/a>) \u0438 <a href=\"https:\/\/medium.com\/nerd-for-tech\/counting-sort-radix-sort-ccd9f77a00a2\" rel=\"noopener noreferrer nofollow\">Counting Radix Sort<\/a> (\u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u043a\u043e\u0434 <a href=\"https:\/\/medium.com\/nerd-for-tech\/counting-sort-radix-sort-ccd9f77a00a2\" rel=\"noopener noreferrer nofollow\">\u043e\u0442\u0441\u044e\u0434\u0430<\/a>). \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e \u043e\u0431\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043f\u0440\u043e\u0438\u0433\u0440\u0430\u043b\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u043c\u0443 <code>Array.Sort<\/code>(<em>\u041a\u043e\u0434 \u044d\u0442\u0438\u0445 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043e\u043a \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0435 \u043f\u0440\u0438\u0432\u043e\u0436\u0443, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0437\u0430\u0431\u0438\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043c, \u043d\u043e \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0435\u0433\u043e \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u0445 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0430\u043c\u0438 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438<\/em>). \u0421\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0431\u043b\u043e\u043a\u043e\u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>SequenceCompareTo<\/code> \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SIMD \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u044b\u0441\u0442\u0440\u0435\u0435, \u0447\u0435\u043c \u0440\u0443\u0447\u043d\u043e\u0439 \u043a\u043e\u0434 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u043f\u043e \u0440\u0430\u0437\u0440\u044f\u0434\u0430\u043c. <\/p>\n<p>\u041a\u043e\u0434 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 <a href=\"https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/sort-key\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/sort-key<\/a><\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u044f \u0443\u0441\u0442\u0430\u043b \u0438 \u043b\u0435\u0433 \u0441\u043f\u0430\u0442\u044c.<\/p>\n<h2>\u0410 \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043a\u043b\u044e\u0447\u0438?<\/h2>\n<p>\u0421 \u044d\u0442\u043e\u0439 \u043c\u044b\u0441\u043b\u044c\u044e \u044f \u043f\u0440\u043e\u0441\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0434\u0435\u043d\u044c. <\/p>\n<ul>\n<li>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u043a\u043b\u044e\u0447\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043a\u043b\u044e\u0447 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 API \u0432  \u0444\u0430\u0437\u0435 \u0441\u043b\u0438\u044f\u043d\u0438\u044f. <\/p>\n<\/li>\n<li>\n<p>\u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445 \u043d\u0430\u043c \u0432\u043e\u043e\u0431\u0449\u0435 \u0434\u0430\u0436\u0435 \u043d\u0435 \u043d\u0430\u0434\u043e \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0432 \u0444\u0430\u0437\u0435 \u0441\u043b\u0438\u044f\u043d\u0438\u044f, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043d\u0443\u0436\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0431\u0430\u0439\u0442 \u0432 \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0412-\u0442\u0440\u0435\u0442\u044c\u0438\u0445, \u0441\u043f\u0443\u0441\u0442\u0438\u0432\u0448\u0438\u0441\u044c \u043d\u0430 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 (<code>FileStream<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>StreamReader<\/code>) \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u042f \u0441\u0434\u0435\u043b\u0430\u043b \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a, \u0433\u0434\u0435 \u0441\u0440\u0430\u0432\u043d\u0438\u043b \u0432\u0441\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u043f\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u043e\u0433\u043e \u0447\u0442\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432, \u0433\u0434\u0435 \u0441\u0440\u0430\u0432\u043d\u0438\u043b <code>File.ReadLines<\/code>, <code>StreamReader<\/code>, <code>FileStream<\/code> \u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0431\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0434\u043d\u044b\u0439 \u043c\u043e\u043b\u043e\u0434\u0435\u0436\u043d\u044b\u0439 <code>PipeReader<\/code>. \u041f\u043e\u0431\u0435\u0434\u0438\u043b, \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e, <code>FileStream<\/code>, \u043a\u0430\u043a \u0441\u0430\u043c\u044b\u0439 \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0447\u0438\u0442\u0430\u0442\u044c \u0438\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438 \u0431\u043b\u043e\u043a\u0430\u043c\u0438, \u0442\u043e \u0432\u044b\u0433\u043e\u0434\u043d\u043e \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0443\u044e \u0431\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044e .NET, \u0430 \u0435\u0441\u043b\u0438 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c\u0438, \u0442\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0431\u0443\u0444\u0435\u0440\u0430 (<em>\u043a\u043e\u0434 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u043e\u0432 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438<\/em>).<\/p>\n<details class=\"spoiler\">\n<summary>\u041c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430<\/summary>\n<div class=\"spoiler__content\">\n<h4>\u0424\u0430\u0437\u0430 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f<\/h4>\n<pre><code class=\"cs\">public void SplitSort() {     using var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, 0, FileOptions.SequentialScan);     fileSize = stream.Length;      List&lt;SortKey> chunk = new();      var keyBuffer = new byte[maxChunkSize];     var readBuffer = new byte[maxChunkSize];     var remainingBytes = 0;      var charBuffer = new char[1024];     var eof = false;     while (!eof)     {         var bytesRead = stream.ReadBlock(readBuffer, remainingBytes, maxChunkSize - remainingBytes, out eof);         int chunkSize = remainingBytes + bytesRead;         if (!eof)         {             var lastNewLine = readBuffer.AsSpan(0, bytesRead).LastIndexOf(NewLine);             if (lastNewLine >= 0) chunkSize = lastNewLine + NewLine.Length;             remainingBytes = remainingBytes + bytesRead - chunkSize;         }          chunk.AddRange(ParseChunk(chunkSize, readBuffer, keyBuffer, charBuffer));          \/\/\u0421\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0447\u0430\u043d\u043a\u0438 \u043d\u0430 \u0434\u0438\u0441\u043a         chunk.Sort(comparer);         WriteChunk(chunk);          chunk.Clear();         \/\/\u041e\u0441\u0442\u0430\u0442\u043e\u043a \u0431\u0443\u0444\u0435\u0440\u0430 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u043c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e         if (remainingBytes > 0) readBuffer.AsSpan(chunkSize, remainingBytes).CopyTo(readBuffer.AsSpan());     } }<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u043a \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043b\u044e\u0447\u0435\u0439 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<pre><code class=\"cs\">private IEnumerable&lt;SortKey> ParseChunk(int byteCount, byte[] readBuffer, byte[] keyBuffer, char[] charBuffer) {     var readPos = 0;     var key = keyBuffer.AsMemory();     while (byteCount > 0)     {         var linePos = readBuffer.AsSpan(readPos, byteCount).IndexOf(NewLine);         if (linePos == -1) linePos = byteCount;         if (charBuffer.Length &lt; linePos) charBuffer = new char[linePos];          \/\/ \u041d\u0430\u0434\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0443 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u043a\u0443, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0430\u043b\u043b\u043e\u0446\u0438\u0440\u0443\u044e\u0442 \u043f\u0430\u043c\u044f\u0442\u044c         var lineLen = encoding.GetChars(readBuffer, readPos, linePos, charBuffer, 0);         var line = charBuffer.AsMemory(0, lineLen);         var s = line.Span;         var dot = s.IndexOf('.');         var x = int.Parse(s[0..dot]);          var keyLen = culture.CompareInfo.GetSortKey(s[(dot + 2)..], key.Span, compareOptions);         BinaryPrimitives.WriteInt32BigEndian(key[keyLen..].Span, x);         keyLen += sizeof(int);          var lineSize = linePos + NewLine.Length;         yield return new SortKey(readBuffer.AsMemory(readPos, lineSize), key[..keyLen]);         key = key[keyLen..];          readPos += lineSize;         byteCount -= lineSize;         maxLineSize = Math.Max(maxLineSize, lineSize);         maxKeyLength = Math.Max(maxKeyLength, keyLen);     } }<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0447\u0430\u043d\u043a\u0430 \u043d\u0430 \u0434\u0438\u0441\u043a<\/p>\n<pre><code class=\"cs\">void WriteChunk(List&lt;SortKey> chunk) {     \/\/ \u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b     var tempFileName = Path.ChangeExtension(file, $\".part-{tempFiles.Count}.tmp\");     using var stream = new FileStream(tempFileName, FileMode.Create, FileAccess.Write, FileShare.None, BufferSize, FileOptions.SequentialScan);              Span&lt;byte> buffer = stackalloc byte[sizeof(int)];     foreach (var (line, key) in chunk)     {         BinaryPrimitives.WriteInt32LittleEndian(buffer, line.Length);         stream.Write(buffer);         stream.Write(line.Span);          BinaryPrimitives.WriteInt32LittleEndian(buffer, key.Length);         stream.Write(buffer);         stream.Write(key.Span);     }     tempFiles.Add(tempFileName); }<\/code><\/pre>\n<h4>\u0424\u0430\u0437\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u044f<\/h4>\n<pre><code class=\"cs\">public void Merge() {     var mergedLines = tempFiles         .Select(ReadTempFile) \/\/ \u0427\u0438\u0442\u0430\u0435\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u043e \u0432\u0441\u0435 \u0444\u0430\u0439\u043b\u044b, \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u0432 \u0441\u0442\u0440\u043e\u043a\u0430\u0445 \u0442\u043e\u0447\u043a\u0443         .Merge(comparer);  \/\/\u0421\u043b\u0438\u044f\u043d\u0438\u0435 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 IEnumerable&lt;IEnumerable&lt;T>> \u0432 IEnumerable&lt;T>      string sortedFileName = Path.ChangeExtension(file, \".sorted\" + Path.GetExtension(file));     using var sortedFile = new FileStream(sortedFileName, FileMode.Create, FileAccess.Write, FileShare.None, BufferSize, FileOptions.SequentialScan);     sortedFile.SetLength(fileSize);     foreach (var (l, _) in mergedLines)     {         sortedFile.Write(l.Span);     } }<\/code><\/pre>\n<p>\u0427\u0442\u0435\u043d\u0438\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430<\/p>\n<pre><code class=\"cs\">private IEnumerable&lt;SortKey> ReadTempFile(string file) {     using var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, FileOptions.SequentialScan);      var maxBlockSize = maxLineSize + maxKeyLength + sizeof(int) * 2;     var readBuffer = new byte[Math.Max(BufferSize, maxBlockSize)];      var bytesRemaining = 0;     var eof = false;      while (!eof)     {         var bytesRead = stream.ReadBlock(readBuffer, bytesRemaining, readBuffer.Length - bytesRemaining, out eof);         if (bytesRead == 0) eof = true;         var mem = readBuffer.AsMemory(0, bytesRemaining + bytesRead);          while (mem.Length > maxBlockSize || (eof &amp;&amp; mem.Length > 0))         {              var lineSize = BinaryPrimitives.ReadInt32LittleEndian(mem.Span);             mem = mem[sizeof(int)..];              var line = mem[..lineSize];             mem = mem[lineSize..];              var keyLen = BinaryPrimitives.ReadInt32LittleEndian(mem.Span);             mem = mem[sizeof(int)..];              yield return new SortKey(line, mem[..keyLen]);             mem = mem[keyLen..];         }          mem.CopyTo(readBuffer);          bytesRemaining = mem.Length;     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418\u0437 25 \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430 \u0432 \u0441\u0430\u043c\u043e\u043c \u043d\u0430\u0447\u0430\u043b\u0435, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u0436\u0435 \u0431\u0435\u0437 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0438 \u043c\u0435\u0442\u043e\u0434\u0430 Main, \u0432\u0441\u0451 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043b\u043e\u0441\u044c \u0432 150 \u0441\u0442\u0440\u043e\u043a \u0431\u0435\u0437 \u0443\u0447\u0435\u0442\u0430 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u0438 \u043f\u043e\u043b\u0435\u0439 \u043a\u043b\u0430\u0441\u0441\u0430.  <\/p>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0437\u0430\u0431\u0435\u0433\u0430 \u043f\u0440\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0447\u0430\u043d\u043a\u0430 \u0432 100\u041c <em>\u0431\u0430\u0439\u0442<\/em>. \u0422\u0430\u043a \u043a\u0430\u043a \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043c\u0435\u0441\u0442\u0435 \u0441\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0438 \u0440\u0430\u0437\u043c\u0435\u0440 \u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u043d\u0430 \u0434\u0438\u0441\u043a\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 180\u041c\u0411.<\/p>\n<pre><code>SplitSort done in 00:04:12.8286312 Merge done in 00:03:05.3477665<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0432\u0435\u043d \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c\u0443, \u043d\u043e \u044d\u0442\u043e \u043f\u0440\u0438 \u0443\u0447\u0435\u0442\u0435 \u0447\u0442\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043f\u0438\u0448\u0435\u043c \u0438 \u0447\u0438\u0442\u0430\u0435\u043c \u043d\u0435 10\u0413\u0431 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432, \u0432 18\u0433\u0431. \u0412 \u0442\u0430\u0441\u043a \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0435 \u0437\u0430\u043c\u0435\u0442\u043d\u043e, \u0447\u0442\u043e \u0431\u044b\u0441\u0442\u0440\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0432 \u0434\u0438\u0441\u043a.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0432 \u0434\u0438\u0441\u043a, \u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u0436\u0430\u0442\u044c. \u0422\u0430\u043a <s>\u043c\u043d\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0430 \u0431\u0430\u0431\u0443\u0448\u043a\u0430<\/s> \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b \u0432 \u043a\u043d\u0438\u0433\u0435 \u043f\u043e \u0431\u0430\u0437\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0445. \u0417\u0430\u0432\u0435\u0440\u043d\u0435\u043c <code>FileStream<\/code> \u0432 <a href=\"https:\/\/learn.microsoft.com\/ru-ru\/dotnet\/api\/system.io.compression.brotlistream\" rel=\"noopener noreferrer nofollow\">BrotliStream<\/a> \u043f\u0440\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438 \u0447\u0442\u0435\u043d\u0438\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432. Brotli \u2014 \u044d\u0442\u043e \u043d\u043e\u0432\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0441\u0436\u0430\u0442\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043a\u0430 \u0435\u0449\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0432 \u0432\u0435\u0431 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0430\u0441\u043f\u0435\u043a\u0442\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0430 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/Brotli\" rel=\"noopener noreferrer nofollow\">\u0432\u0438\u043a\u0438\u043f\u0435\u0434\u0438\u0438<\/a>.<\/p>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0437\u0430\u0431\u0435\u0433\u0430 \u0441\u043e \u0441\u0436\u0430\u0442\u0438\u0435\u043c<\/p>\n<pre><code>SplitSort done in 00:04:28.3044728 Merge done in 00:00:36.4300613<\/code><\/pre>\n<p>\u0412 \u0441\u0443\u043c\u043c\u0435 \u043c\u0435\u043d\u044c\u0448\u0435 5 \u043c\u0438\u043d\u0443\u0442. \u0421\u0443\u043c\u043c\u0430\u0440\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0430 \u0434\u0438\u0441\u043a\u0435 \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u043b\u0441\u044f \u0434\u043e 970\u041c\u0411, \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u043e\u0447\u0442\u0438 \u0432 20 \u0440\u0430\u0437. \u042d\u0442\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0449\u0438\u0445\u0441\u044f \u0441\u0442\u0440\u043e\u043a. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u0430\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0434\u0430\u044e\u0449\u0438\u043c\u0441\u044f, \u043d\u043e \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u043e\u043c \u0438\u043b\u0438 chatGpt \u0442\u0435\u043a\u0441\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u0445\u043e\u0440\u043e\u0448\u0438 \u0441\u0436\u0438\u043c\u0430\u0442\u044c\u0441\u044f. <\/p>\n<p>\u041a\u043e\u0434 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 <a href=\"https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/sort-key-with-compression\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/sort-key-with-compression<\/a><\/p>\n<p>\u0411\u044b\u0441\u0442\u0440\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u0443\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043d\u0435 \u0432 \u0434\u0438\u0441\u043a, \u0430 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440. \u0418 \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u043e. \u0414\u0438\u0441\u043a \u0443 \u043d\u0430\u0441 \u043e\u0434\u0438\u043d, \u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u043e\u0432 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0431\u043e\u043b\u044c\u0448\u0435.<\/p>\n<h2>\u0420\u0430\u0441\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0432\u0430\u043d\u0438\u0435<\/h2>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e:<\/p>\n<ol>\n<li>\n<p>\u0427\u0442\u0435\u043d\u0438\u0435 \u0447\u0430\u043d\u043a\u0430 (\u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0434\u0438\u0441\u043a \u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440)<\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u0441\u0438\u043d\u0433 \u0441\u0442\u0440\u043e\u043a \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0435\u0439 (\u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c)<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 (\u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440)<\/p>\n<\/li>\n<li>\n<p>\u0421\u0436\u0430\u0442\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440)<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0438\u0441\u044c (\u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0434\u0438\u0441\u043a)<\/p>\n<\/li>\n<\/ol>\n<p>\u0411\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u043f\u0443\u043d\u043a\u0442\u044b 1 \u0438 5 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441 2-4. <\/p>\n<p>\u0417\u0430\u0432\u0435\u0434\u0435\u043c \u043f\u044f\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438. \u0414\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0447\u0430\u043d\u043a\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/an-introduction-to-system-threading-channels\/\" rel=\"noopener noreferrer nofollow\">System.Threading.Channels<\/a>. <\/p>\n<pre><code class=\"cs\">readToParse = Channel.CreateBounded&lt;(byte[], int)>(1); \/\/ \u0411\u0443\u0444\u0435\u0440 \u0438 \u0440\u0430\u0437\u043c\u0435\u0440 parseToSort = Channel.CreateBounded&lt;(List&lt;SortKey>, byte[], byte[])>(1);     \/\/ \u0421\u043f\u0438\u0441\u043e\u043a \u043a\u043b\u044e\u0447\u0435\u0439, \u0431\u0443\u0444\u0435\u0440 \u0441\u0442\u0440\u043e\u043a \u0438 \u0431\u0443\u0444\u0435\u0440 \u043a\u043b\u044e\u0447\u0435\u0439 sortToCompress = Channel.CreateBounded&lt;(List&lt;SortKey>, byte[], byte[])>(1)); \/\/ \u0421\u043f\u0438\u0441\u043e\u043a \u043a\u043b\u044e\u0447\u0435\u0439, \u0431\u0443\u0444\u0435\u0440 \u0441\u0442\u0440\u043e\u043a \u0438 \u0431\u0443\u0444\u0435\u0440 \u043a\u043b\u044e\u0447\u0435\u0439 compressToWrite = Channel.CreateBounded&lt;(byte[], int)>(1); \/\/ \u0421\u0436\u0430\u0442\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0440\u0430\u0437\u043c\u0435\u0440  parserThreads =     Enumerable     .Range(0, degreeOfParallelism)     .Select(_ => Task.Run(ParallelParser)).ToArray();  sorterThreads =     Enumerable     .Range(0, degreeOfParallelism)     .Select(_ => Task.Run(ParallelSorter)).ToArray();  compressThreads =     Enumerable     .Range(0, degreeOfParallelism)     .Select(_ => Task.Run(ParallelCompressor)).ToArray();  writerThread = Task.Run(ParallelWriter);<\/code><\/pre>\n<p>\u041d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b \u0441 \u0435\u043c\u043a\u043e\u0441\u0442\u044c\u044e \u0432 \u043e\u0434\u043d\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435. \u0415\u0441\u043b\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438, \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u0438 \u0437\u0430\u043d\u044f\u0442\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e, \u0442\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u0432\u0438\u0441\u0435\u0442\u044c \u0432 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043a\u0430\u043d\u0430\u043b\u0430. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f.<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>SplitSort<\/code> \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043c\u043e\u0433 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u0430\u043a \u0432 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435, \u0442\u0430\u043a \u0438 \u0432 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u043c<\/p>\n<pre><code class=\"cs\">using var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, 0, FileOptions.SequentialScan); fileSize = stream.Length;  List&lt;SortKey>? chunk = null; byte[]? keyBuffer = null; char[]? charBuffer = null;  var readBuffer = pool!.Rent(maxChunkSize); var remainingBytes = 0; var eof = false;   while (!eof) {     var bytesRead = stream.ReadBlock(readBuffer, remainingBytes, maxChunkSize - remainingBytes, out eof);     int chunkSize = remainingBytes + bytesRead;     if (!eof)     {         var lastNewLine = readBuffer.AsSpan(0, bytesRead).LastIndexOf(NewLine);         if (lastNewLine >= 0) chunkSize = lastNewLine + NewLine.Length;         remainingBytes = remainingBytes + bytesRead - chunkSize;     }      var oldBuffer = readBuffer;     if (degreeOfParallelism > 0)     {         await readToParse.Writer.WriteAsync((readBuffer, chunkSize));         readBuffer = pool.Rent(maxChunkSize);     }     else     {         chunk ??= new();          chunk.AddRange(ParseChunk(chunkSize, readBuffer,             keyBuffer ??= pool.Rent(maxChunkSize),             charBuffer ??= new char[1024]));          \/\/\u0421\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0447\u0430\u043d\u043a\u0438 \u043d\u0430 \u0434\u0438\u0441\u043a         chunk.Sort(comparer);         WriteChunk(chunk);         chunk.Clear();     }      \/\/\u041e\u0441\u0430\u0442\u043e\u043a \u0431\u0443\u0444\u0435\u0440\u0430 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u043c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e     if (remainingBytes > 0) oldBuffer.AsSpan(chunkSize, remainingBytes).CopyTo(readBuffer.AsSpan()); }  if (degreeOfParallelism == 0) {     if (readBuffer != null) pool.Return(readBuffer);     if (keyBuffer != null) pool.Return(keyBuffer); }<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>degreeOfParallelism<\/code> \u0440\u0430\u0432\u0435\u043d \u043d\u0443\u043b\u044e, \u0442\u043e \u043a\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043a\u0430\u043a \u0438 \u0440\u0430\u043d\u044c\u0448\u0435. \u0415\u0441\u043b\u0438 <code>degreeOfParallelism >= 1<\/code>, \u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u0447\u0442\u0435\u043d\u0438\u044f \u0447\u0430\u043d\u043a\u0430 \u043e\u043d \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0432 <code>readToParse<\/code> \u043a\u0430\u043d\u0430\u043b \u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u043d\u0430\u0447\u043d\u0435\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u043d\u043a.<\/p>\n<p>\u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0434\u043d\u0438\u043c \u0431\u0443\u0444\u0435\u0440\u043e\u043c \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a \u0438 \u043a\u043b\u044e\u0447\u0435\u0439 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f, \u0431\u0443\u0444\u0435\u0440\u044b \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0432\u044b\u0434\u0435\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0435. \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0437\u0430\u0431\u0438\u0442\u044c \u0432\u0441\u044e \u043f\u0430\u043c\u044f\u0442\u044c \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u044f \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b <a href=\"https:\/\/learn.microsoft.com\/ru-ru\/dotnet\/api\/system.buffers.arraypool-1\" rel=\"noopener noreferrer nofollow\">ArrayPool<\/a>. \u041d\u0438\u0447\u0435\u0433\u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e \u043d\u0435\u0442: \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <strong>new<\/strong> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>Rent<\/code>, \u0430 \u043a\u043e\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f &#8212; \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c <code>Return<\/code>.<\/p>\n<p><code>ParallelParser<\/code>, <code>ParallelSorter<\/code> \u0438 <code>ParallelWriter<\/code> \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"cs\">private async Task ParallelParser() {     var charBuffer = new char[1024];     await foreach (var (readBuffer, chunkSize) in readToParse.Reader.ReadAllAsync())     {         var keyBuffer = pool!.Rent(maxChunkSize);         var chunk = ParseChunk(chunkSize, readBuffer, keyBuffer, charBuffer).ToList();         await parseToSort.Writer.WriteAsync((chunk, readBuffer, keyBuffer));      } }  private async Task ParallelSorter() {     await foreach (var item in parseToSort.Reader.ReadAllAsync())     {         item.Item1.Sort(comparer);         await sortToCompress.Writer.WriteAsync(item);     } }  private async Task ParallelWriter() {     await foreach (var (buffer, bufferLength) in compressToWrite.Reader.ReadAllAsync())     {         var tempFileName = Path.ChangeExtension(file, $\".part-{tempFiles.Count}.tmp\");         using (var tempFile = new FileStream(tempFileName, FileMode.Create, FileAccess.Write, FileShare.None, 0, FileOptions.SequentialScan))         {              await tempFile.WriteAsync(buffer.AsMemory(0, bufferLength));         }         pool!.Return(buffer);         tempFiles.Add(tempFileName);     } }<\/code><\/pre>\n<p>\u041e\u043d\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u043f\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443 &#8212; \u0447\u0438\u0442\u0430\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438\u0437 \u043a\u0430\u043d\u0430\u043b\u0430 \u043f\u043e\u043a\u0430 \u043e\u043d\u0438 \u043d\u0435 \u043a\u043e\u043d\u0447\u0430\u0442\u0441\u044f, \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u0432\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<p>ParallelCompressor \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d \u043f\u043e \u0442\u043e\u043c\u0443 \u0436\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443, \u043d\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u043a\u043e\u0434\u0430. \u0423\u0431\u0435\u0440\u0443 \u0435\u0433\u043e \u043f\u043e\u0434 \u0441\u043f\u043e\u0439\u043b\u0435\u0440.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 ParallelCompressor<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">private async Task ParallelCompressor() {     var buffer = new byte[1024]; \/\/Buffer with margin     var outputSize = BrotliEncoder.GetMaxCompressedLength(maxChunkSize * 2);     await foreach (var (chunk, readBuffer, keyBuffer) in sortToCompress.Reader.ReadAllAsync())     {         using var encoder = new BrotliEncoder(4, 22);         var output = pool!.Rent(outputSize);         var dest = output.AsMemory();          var compressed = 0;         foreach (var sk in chunk)         {             if (sk.Length > buffer.Length)             {                 buffer = new byte[sk.Length];             }              sk.Write(buffer, 0);              var source = buffer.AsMemory(0, sk.Length);             while (true)             {                 var r = encoder.Compress(source.Span, dest.Span, out var bytesConsumed, out var bytesWritten, false);                 compressed += bytesWritten;                 if (bytesConsumed > 0) source = source[bytesConsumed..];                 if (bytesWritten > 0) dest = dest[bytesWritten..];                 if (r == OperationStatus.Done) break;                 if (r == OperationStatus.InvalidData || r == OperationStatus.NeedMoreData)                 {                     throw new InvalidOperationException();                 }                 var old = output;                 outputSize *= 2;                 output = pool.Rent(outputSize);                  old.CopyTo(output, 0);                 pool.Return(old);                 dest = output.AsMemory(compressed);              }         }          while (true)         {             var r = encoder.Flush(dest.Span, out var bytesWritten);             compressed += bytesWritten;             if (r == OperationStatus.Done) break;             if (r == OperationStatus.InvalidData || r == OperationStatus.NeedMoreData)             {                 throw new InvalidOperationException();             }             var old = output;             outputSize *= 2;             output = pool.Rent(outputSize);              old.CopyTo(output, 0);             pool.Return(old);             dest = output.AsMemory(compressed);         }         outputSize = compressed * 11 \/ 10;         await compressToWrite.Writer.WriteAsync((output, compressed));          pool.Return(readBuffer);         pool.Return(keyBuffer);     } }<\/code><\/pre>\n<p>\u0418\u0437 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u0442\u0440\u043e\u043a \u0438 \u043a\u043b\u044e\u0447\u0435\u0439 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435 \u0432 \u044d\u043d\u043a\u043e\u0434\u0435\u0440, \u0430 \u043e\u043d \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u0434\u0430\u0435\u0442 \u043d\u0430\u043c \u0431\u043b\u043e\u043a \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043d\u0430\u0434\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c Flush. \u0412\u0441\u0435 \u043e\u0441\u043b\u043e\u0436\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c\u0441\u044f \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u0438 \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043c\u0435\u0441\u0442\u0430 \u0432 \u0446\u0435\u043b\u0435\u0432\u043e\u043c \u0431\u0443\u0444\u0435\u0440\u0435. \u0422\u043e\u0433\u0434\u0430 \u043d\u0430\u0434\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u0431\u0443\u0444\u0435\u0440 \u043f\u043e\u0431\u043e\u043b\u044c\u0448\u0435 \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0442\u0443\u0434\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0441\u0442\u0430\u0440\u043e\u0433\u043e.<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u0434 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438: \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0438 \u0436\u0434\u0435\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0432.<\/p>\n<pre><code class=\"cs\">readToParse.Writer.Complete(); await parserThread; parseToSort.Writer.Complete(); await sorterThread; sortToCompress.Writer.Complete(); await compressThread; compressToWrite.Writer.Complete(); await writerThread;<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0447\u0430\u043d\u043a\u0430  \u0432 200 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442<em>.<\/em><\/p>\n<pre><code>SplitSort done in 00:02:21.4203828 Merge done in 00:00:39.0610435<\/code><\/pre>\n<p>\u0422\u0440\u0438 \u043c\u0438\u043d\u0443\u0442\u044b \u0432 \u0441\u0443\u043c\u043c\u0435, \u0435\u0441\u0442\u044c \u0448\u0430\u043d\u0441 \u0443\u043b\u043e\u0436\u0438\u0442\u044c\u0441\u044f \u0432 \u0447\u0430\u0441 \u0434\u043b\u044f 100\u0413\u0431.<\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432 \u0442\u0430\u0441\u043a \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d15\/2c8\/feb\/d152c8feb6d1d1c46581f2cf01c7d940.png\" width=\"1894\" height=\"891\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d15\/2c8\/feb\/d152c8feb6d1d1c46581f2cf01c7d940.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u043c\u044f\u0442\u0438 \u0432\u044b\u0440\u043e\u0441\u043b\u043e \u0441 400\u041c\u0431 \u0434\u043e 5,3\u0413\u0431, \u044d\u0442\u043e \u0443\u0436\u0435 \u043c\u043d\u043e\u0433\u043e. \u041f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a?<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043a\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u043e\u0434\u0438\u043d \u043d\u0430\u0431\u043e\u0440 \u0431\u0443\u0444\u0435\u0440\u043e\u0432 &#8212; \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0434\u043b\u044f \u043a\u043b\u044e\u0447\u0435\u0439, \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043b\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0438 \u0431\u0443\u0444\u0435\u0440 \u0434\u043b\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430. \u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u0435\u0440\u0435\u0448\u043b\u0438 \u0432 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0443 \u043d\u0430\u0441 \u0442\u0430\u043a\u0438\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 + \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443 \u043a\u0430\u043d\u0430\u043b\u043e\u0432 \u0438 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0445 \u043c\u0435\u0441\u0442 \u0432 \u043d\u0438\u0445.<\/p>\n<p>\u0422\u0430\u043a\u043e\u0432\u0430, \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, <strong>\u0446\u0435\u043d\u0430 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438<\/strong>. \u041e\u0447\u0435\u043d\u044c \u0440\u0435\u0434\u043a\u043e \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0435 \u043f\u043e\u0432\u044b\u0448\u0430\u044f \u0440\u0430\u0437\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438.<\/p>\n<p>\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u0434\u0438\u0441\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f, \u0441\u0442\u043e\u0438\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430, \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0438 \u0441\u0436\u0430\u0442\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u043e \u0435\u0441\u0442\u044c \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c <em>\u0441\u0442\u0435\u043f\u0435\u043d\u044c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c\u0430<\/em> (<em>dop<\/em>). \u041d\u043e \u044d\u0442\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442 \u0437\u0430\u0442\u0440\u0430\u0442\u044b \u043f\u0430\u043c\u044f\u0442\u0438. \u041c\u043e\u0436\u043d\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440 \u0447\u0430\u043d\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u0438 \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c\u0430.<\/p>\n<pre><code class=\"cs\">\/\/ \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e dop = Environment.ProcessorCount \/ 4; chunkSize = 200 \/ int.Max(dop, 1);<\/code><\/pre>\n<p>\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0433\u043e\u043d \u0441 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 (dop=4, chunkSize=50)<\/p>\n<pre><code>SplitSort done in 00:00:53.8610345 Merge done in 00:00:39.7727140<\/code><\/pre>\n<p>\u0418\u0442\u043e\u0433\u043e 1:40 (\u043d\u0435 \u0431\u043e\u043b\u0435\u0435 1:50 \u0437\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432).<\/p>\n<p>\u041a\u043e\u0434 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0430\u043c\u0438 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 <a href=\"https:\/\/github.com\/gandjustas\/HugeFileSort\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gandjustas\/HugeFileSort<\/a><\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u042f \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0448\u0438\u0431\u0441\u044f, \u0434\u0443\u043c\u0430\u044f \u0447\u0442\u043e \u0437\u0430\u0434\u0430\u0447\u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 100\u0413\u0431 \u0444\u0430\u0439\u043b\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f. \u0414\u043b\u044f \u0435\u0451 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0443\u0436\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u043d\u0438\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432, \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u043d\u0430\u0432\u044b\u043a \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430.  \u0410 \u0441\u0430\u043c\u043e\u0435 \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u044d\u0442\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043b\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 \u043f\u0440\u0435\u043e\u0434\u043e\u043b\u0435\u0432\u0430\u0442\u044c \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0438 \u0438 \u0440\u0435\u0448\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443 \u0434\u043e \u043a\u043e\u043d\u0446\u0430, \u0430 \u043d\u0435 \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0439\u0442\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 \u043f\u0443\u0441\u0442\u044c \u0438 \u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0440\u0443\u043a\u0438, \u0435\u0441\u043b\u0438 \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u0443\u0442\u0438 \u043d\u0435\u0442.<\/p>\n<h2>PS<\/h2>\n<pre><code>\u276f .\\Sort.exe ..\\..\\..\\..\\100gb.txt SplitSort done in 00:11:35.9023876 Merge done in 00:20:16.3989011<\/code><\/pre>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/714524\/\"> https:\/\/habr.com\/ru\/post\/714524\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043d\u0442\u043e\u0440\u0435 \u0441\u043e\u0438\u0441\u043a\u0430\u0442\u0435\u043b\u044e \u043d\u0430 \u043f\u043e\u0437\u0438\u0446\u0438\u044e Senior C# developer \u0432\u044b\u0434\u0430\u043b\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435: \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u0441\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430.<\/p>\n<p>\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0430\u043a\u0438\u0435:<\/p>\n<ul>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430\u0442 \u0441\u0442\u0440\u043e\u043a\u0438: \u0447\u0438\u0441\u043b\u043e, \u0442\u043e\u0447\u043a\u0430, \u043f\u0440\u043e\u0431\u0435\u043b, \u0434\u0430\u043b\u0435\u0435 \u043b\u044e\u0431\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u0441\u0442\u0440\u043e\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u2014 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0440\u043e\u043a\u0438, \u043f\u043e\u0442\u043e\u043c \u043f\u043e \u0447\u0438\u0441\u043b\u0443 \u0435\u0441\u043b\u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430 \u2014 UTF-8<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430 \u2014 100\u0433\u0431 &#8212; \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043e\u0431\u044a\u0435\u043c\u0430 \u041e\u041f<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u043b\u0436\u043d\u043e \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0437\u0430 1 \u0447\u0430\u0441 \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0449\u0435\u0433\u043e, \u0432\u0440\u044f\u0434 \u043b\u0438 \u0442\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u0443\u043f\u0435\u0440-\u0431\u044b\u0441\u0442\u0440\u044b\u0439 SSD \u0438 \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u0430\u043a \u0438 \u043c\u043d\u043e\u0433\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u044b, \u0443\u0437\u043d\u0430\u0432 \u043e \u0442\u0430\u043a\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0437\u0430\u0434\u0430\u043d\u0438\u0438, \u044f \u0432\u043e\u0437\u043c\u0443\u0442\u0438\u043b\u0441\u044f. \u0412\u043d\u0435\u0448\u043d\u044e\u044e \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u0441\u043b\u0438\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043b\u0438 \u0432 \u0412\u0423\u0417\u0435, \u043d\u043e \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0438\u043a\u0442\u043e \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043f\u0438\u0441\u0430\u043b \u0435\u0451. \u0417\u0430\u0434\u0430\u0447\u0430 \u043e\u0447\u0435\u043d\u044c \u043d\u0435\u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0438 \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e \u043a\u0430\u043a\u0438\u0435 \u043d\u0430\u0432\u044b\u043a\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442. \u0422\u0430\u043a \u043c\u043d\u0435 \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c.<\/p>\n<p>\u042d\u0442\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u0432\u044b\u0437\u0432\u0430\u043b\u0430 \u0431\u0443\u0440\u043d\u044b\u0435 \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u044f \u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u0445 \u0435\u0451 \u0440\u0435\u0448\u0435\u043d\u0438\u044f. \u041c\u043d\u043e\u0433\u0438\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u044b, \u043f\u0440\u0438\u0447\u0438\u0441\u043b\u044f\u044e\u0449\u0438\u0435 \u0441\u0435\u0431\u044f \u043a \u0440\u0430\u043d\u0433\u0443 senior, \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0438\u0431\u043e \u043d\u0435 \u0431\u0430\u0440\u0441\u043a\u043e\u0435 \u044d\u0442\u043e \u0434\u0435\u043b\u043e &#8212; \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0438\u0441\u0430\u0442\u044c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0430\u0436\u0435 \u043f\u043e\u043f\u044b\u0442\u0430\u043b\u0438\u0441\u044c  \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 Apache Spark. \u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0438\u043a\u0442\u043e \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u0437\u0430\u0434\u0430\u0447\u0443 \u043d\u0435 \u0440\u0435\u0448\u0438\u043b, \u0438\u0431\u043e \u043c\u0430\u043b\u043e \u043a\u043e\u043c\u0443 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u0434\u0430\u0436\u0435 10\u0413\u0411 \u0444\u0430\u0439\u043b \u043c\u0435\u043d\u0435\u0435 \u0447\u0435\u043c \u0437\u0430 15 \u043c\u0438\u043d\u0443\u0442 \u0431\u0435\u0437 SSD.<\/p>\n<p>\u042f \u043f\u043e\u0434\u0443\u043c\u0430\u043b, \u0447\u0442\u043e \u0441\u0442\u043e\u0438\u0442 \u0440\u0435\u0448\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443 \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0438 \u0442\u043e\u0436\u0435 \u043f\u0440\u0438\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0441\u0435\u0431\u044f \u043a \u0440\u0430\u043d\u0433\u0443 senior developer.<\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043d\u0443\u0436\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0437\u044f\u043b \u043f\u0435\u0440\u0432\u044b\u0439 \u0442\u043e\u043c \u0412\u043e\u0439\u043d\u044b \u0438 \u041c\u0438\u0440\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u043a\u0430\u043a \u0440\u0443\u0441\u0441\u043a\u0438\u0435, \u0442\u0430\u043a \u0438 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b.  <\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">var source = (from l in File.ReadLines(\"source.txt\")               where !string.IsNullOrEmpty(l)               from s in l.Split(new[] { '.', '?', '!', '[', ']' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)               where s.Length > 10               select s).ToList();  Random rand = new();  using (var f = File.CreateText(file)) {     f.AutoFlush = false;     while(f.BaseStream.Position &lt; maxSize)     {         var n = rand.Next();         f.Write(n);         f.Write(\". \");         f.WriteLine(source[rand.Next(source.Count)]);     } } return 0;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0435\u0448\u0438\u043b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c 10\u0413\u0411, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0436\u0434\u0430\u0442\u044c \u0447\u0430\u0441 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u043f\u0440\u043e\u0433\u043e\u043d\u0435. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b \u0442\u0430\u043a\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043d\u0435 \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u044d\u0448\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0447\u0442\u0435\u043d\u0438\u044f-\u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u043e\u0445\u043e\u0434\u044f\u0442 \u0434\u043e \u0434\u0438\u0441\u043a\u0430, \u0447\u0442\u043e \u0434\u0430\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0431\u044b\u0441\u0442\u0440\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043e\u0431\u044a\u0435\u043c\u0430\u0445.<\/p>\n<h2>\u0421\u0430\u043c\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412\u0441\u0435 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441\u043e <a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/712234\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430 \u0445\u0430\u0431\u0440\u0435 \u043e \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0435<\/a>. \u0421\u0440\u0430\u0437\u0443 \u043e\u0442\u0431\u0440\u043e\u0441\u0438\u043b \u0438\u0434\u0435\u044e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432 \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0431\u043b\u043e\u043a\u043e\u0432, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u043b\u043e \u0431\u044b \u043a \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0437\u0430\u0442\u0440\u0430\u0442\u0430\u043c \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c. \u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043b \u043d\u0430 \u0434\u0432\u0435 \u0444\u0430\u0437\u044b \u2014 <em>\u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435<\/em> \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 (<em>\u0447\u0430\u043d\u043a\u0438<\/em>, \u043e\u0442 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u0433\u043e <em>chunk<\/em>) \u0438 <em>\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430<\/em> \u0441\u0442\u0440\u043e\u043a \u0432 \u0431\u043b\u043e\u043a\u0430\u0445, <em>\u0441\u043b\u0438\u044f\u043d\u0438\u0435<\/em> \u0431\u043b\u043e\u043a\u043e\u0432 \u0432 \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b.<\/p>\n<p>\u041a\u043e\u0434 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f<\/p>\n<pre><code class=\"cs\">var count = 0; var tempFiles =     File.ReadLines(file)         .Select(s => new Item(s, s.IndexOf('.')))         .Chunk(chunkSize)         .Select(chunk =>         {             Array.Sort(chunk, comparer);             var tempFileName = Path.ChangeExtension(file, $\".part-{count++}\" + Path.GetExtension(file));             File.WriteAllLines(tempFileName, chunk.Select(x => x.Line));             return tempFileName;         }).ToList();<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u0441\u043b\u0438\u044f\u043d\u0438\u044f<\/p>\n<pre><code class=\"cs\">try {     var mergedLines = tempFiles         .Select(f => File.ReadLines(f).Select(s => new Item(s, s.IndexOf('.'))))         .Merge(comparer) \/\/ IEnumerable&lt;IEnumerable&lt;T>> -> IEnumerable&lt;T>         .Select(x => x.Line);     File.WriteAllLines(Path.ChangeExtension(file, \".sorted\" + Path.GetExtension(file)), mergedLines); } finally {     tempFiles.ForEach(File.Delete); }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u0442\u0438\u043f, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0442\u043e\u0447\u043a\u0438 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u0438 \u043a\u043e\u043c\u043f\u0430\u0440\u0430\u0442\u043e\u0440 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430<\/p>\n<pre><code class=\"cs\">public record struct Item(string Line, int DotPosition); public record Comparer(StringComparison StringComparison) : IComparer&lt;Item> {     public int Compare(Item x, Item y)     {         var spanX = x.Line.AsSpan();         var spanY = y.Line.AsSpan();         var xDot = x.DotPosition;         var yDot = y.DotPosition;          var cmp = spanX[(xDot + 2)..].CompareTo(spanY[(yDot + 2)..], StringComparison);         if (cmp != 0) return cmp;         return int.Parse(spanX[..xDot]) - int.Parse(spanY[..yDot]);     } }<\/code><\/pre>\n<p> &#171;\u0421\u0435\u0440\u0434\u0446\u0435&#187; \u0432\u0441\u0435\u0433\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 &#8212; \u0441\u043b\u0438\u044f\u043d\u0438\u0435 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 <\/p>\n<pre><code class=\"cs\">public static IEnumerable&lt;T> Merge&lt;T>(this IEnumerable&lt;IEnumerable&lt;T>> sources, IComparer&lt;T> comparer = default) {     var enumerators = (from source in sources                         let e = source.GetEnumerator()                         where e.MoveNext()                         select e).ToList();                  while (enumerators.Count > 0)     {         var min = enumerators.MinBy(e => e.Current, comparer)!;         yield return min.Current;         if (!min.MoveNext())         {             min.Dispose();             enumerators.Remove(min);         }     } }<\/code><\/pre>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u044f \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b async\\await? \u0412\u0435\u0434\u044c \u0441\u0435\u0439\u0447\u0430\u0441 \u0432\u0441\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u044b C# \u0432\u0442\u044b\u043a\u0430\u044e\u0442 <strong>async<\/strong>\\<strong>await<\/strong> \u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0435. \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u044f \u0442\u043e\u0436\u0435 \u0442\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u043b \u0441\u043d\u0430\u0447\u0430\u043b\u0430, \u043d\u043e \u043f\u043e\u0442\u043e\u043c \u0443\u0431\u0440\u0430\u043b.<\/p>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445 \u0434\u043b\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c Merge. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445 \u043a\u043e\u0434 \u0441 <strong>async<\/strong>\\<strong>await <\/strong>\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u043b. <strong>async<\/strong>\\<strong>await<\/strong> \u043d\u0435\u0441\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0440\u0430\u0441\u0445\u043e\u0434\u044b \u043d\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 \u0432\u0441\u044e \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u0433\u043e\u0434\u043d\u043e \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0440\u0430\u0441\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0442\u044c <em>\u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435<\/em>, \u043d\u043e \u0432 \u044d\u0442\u043e\u043c \u043a\u043e\u0434\u0435 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0439 \u043d\u0435\u0442. \u0412\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<h2>\u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a<\/h2>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u0441\u043b\u0438\u044f\u043d\u0438\u0435\u043c, \u0440\u0430\u0437\u043c\u0435\u0440 \u0447\u0430\u043d\u043a\u0430 &#8212; 1\u041c \u0441\u0442\u0440\u043e\u043a \u0438\u043b\u0438 \u043e\u043a\u043e\u043b\u043e 157\u041c\u0431, \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b &#8212; 15:30, \u043f\u044f\u0442\u043d\u0430\u0434\u0446\u0430\u0442\u044c \u0441 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u043e\u0439 \u043c\u0438\u043d\u0443\u0442! \u0412 \u0447\u0430\u0441 \u0434\u043b\u044f 100\u0413\u0431 \u0443\u043b\u043e\u0436\u0438\u0442\u044c\u0441\u044f \u043d\u0435 \u0432\u044b\u0439\u0434\u0435\u0442.<\/p>\n<p>\u0427\u0442\u043e \u043f\u043e \u0432\u0430\u0448\u0435\u043c\u0443 \u0442\u043e\u0440\u043c\u043e\u0437\u0438\u043b\u043e \u0432 \u044d\u0442\u043e\u043c \u043a\u043e\u0434\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e? \u041d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0441\u0432\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0441\u043f\u043e\u0439\u043b\u0435\u0440 \u0438 \u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u0422\u0430\u0439\u043c\u0438\u043d\u0433<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>SplitSort done in 00:04:59.2942000 Merge done in 00:10:32.1238153<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u0437\u0430\u0434\u0430\u0447 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b, \u0447\u0442\u043e \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430 \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u043c\u0430\u043b\u043e<\/p>\n<figure class=\"full-width\"><figcaption>\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0432 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f (\u0426\u041f7 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b \u043a\u043e\u0434)<\/figcaption><\/figure>\n<figure class=\"full-width\"><figcaption>\u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u0434\u0438\u0441\u043a \u0432 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f<\/figcaption><\/figure>\n<p>\u041a\u043e\u0434 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 <a href=\"https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/naive\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/naive<\/a><\/p>\n<h2>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0441\u043b\u0438\u044f\u043d\u0438\u0435<\/h2>\n<p>\u0414\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0435 \u0447\u0442\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c, \u0430 \u043f\u043e\u0438\u0441\u043a \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043b\u0438\u044f\u043d\u0438\u044f. \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u044f \u0447\u0435\u0441\u0442\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0430\u043c, \u043d\u0435 \u043f\u043e\u0434\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044f \u0432 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f. \u0413\u043e\u0440\u0430\u0437\u0434\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0430\u00a0\u0434\u0430\u043b\u0435\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0438\u0445 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 <em>.MoveNext()<\/em>, \u0434\u0430\u0436\u0435 <a href=\"https:\/\/stackoverflow.com\/questions\/2767007\/most-efficient-algorithm-for-merging-sorted-ienumerablet\" rel=\"noopener noreferrer nofollow\">\u043d\u0430 StackOverflow<\/a> \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442 \u0442\u0430\u043a\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442.<\/p>\n<p>\u041b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442 <a href=\"https:\/\/habr.com\/ru\/post\/112222\/\" rel=\"noopener noreferrer nofollow\">\u0434\u0432\u043e\u0438\u0447\u043d\u0430\u044f (\u043e\u043d\u0430 \u0436\u0435 \u0431\u0438\u043d\u0430\u0440\u043d\u0430\u044f) \u043a\u0443\u0447\u0430<\/a>. \u041e\u043d\u0430 \u0438\u043c\u0435\u0435\u0442 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u043a\u043e\u0440\u043d\u0435 \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u0437\u0430 O(logN), \u0433\u0434\u0435 K &#8212; \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u043a\u0443\u0447\u0435 (\u0443 \u043d\u0430\u0441 \u0440\u0430\u0432\u043d\u043e \u0447\u0438\u0441\u043b\u0443 \u0447\u0430\u043d\u043a\u043e\u0432). \u0415\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u044f \u043d\u0435 \u0441\u0430\u043c \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u043b, \u0430 \u043f\u043e\u0434\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u041c\u0435\u0442\u043e\u0434\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u0443\u0447\u0435\u0439<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">public static void Heapify&lt;T>(this Span&lt;T> heap, int index, IComparer&lt;T> comparer) {     ArgumentNullException.ThrowIfNull(comparer);      var min = index;     while (true)     {         var leftChild = 2 * index + 1;         var rightChild = 2 * index + 2;         var v = heap[index];          if (rightChild &lt; heap.Length &amp;&amp; comparer.Compare(v, heap[rightChild]) > 0)         {             min = rightChild;             v = heap[min];         }          if (leftChild &lt; heap.Length &amp;&amp; comparer.Compare(v, heap[leftChild]) > 0)         {             min = leftChild;         }          if (min == index) break;          var temp = heap[index];         heap[index] = heap[min];         heap[min] = temp;          index = min;     } }  public static void BuildHeap&lt;T>(this Span&lt;T> heap, IComparer&lt;T> comparer) {     ArgumentNullException.ThrowIfNull(comparer);      for (int i = heap.Length \/ 2; i >= 0; i--)     {         Heapify(heap, i, comparer);     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041a\u043e\u0434 \u043c\u0435\u0442\u043e\u0434\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u044f<\/p>\n<pre><code class=\"cs\">public static IEnumerable&lt;T> Merge&lt;T>(this IEnumerable&lt;IEnumerable&lt;T>> sources, IComparer&lt;T> comparer = default) {     var heap = (from source in sources                 let e = source.GetEnumerator()                 where e.MoveNext()                 select e).ToArray();      var enumeratorComparer = new EnumeratorComparer&lt;T>(comparer ?? Comparer&lt;T>.Default);     heap.AsSpan().BuildHeap(enumeratorComparer);      while (true)     {         var min = heap[0];         yield return min.Current;         if (!min.MoveNext())         {             min.Dispose();             if (heap.Length == 1) yield break;             heap[0] = heap[^1];             Array.Resize(ref heap, heap.Length - 1);         }         heap.AsSpan().Heapify(0, enumeratorComparer);     } }  private record EnumeratorComparer&lt;T>(IComparer&lt;T> comparer) : IComparer&lt;IEnumerator&lt;T>> {     public int Compare(IEnumerator&lt;T>? x, IEnumerator&lt;T>? y)     {         return comparer.Compare(x!.Current, y!.Current);     } }<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u0434 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f. \u0412\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b:<\/p>\n<pre><code>SplitSort done in 00:04:27.8391844 Merge done in 00:02:11.4364005<\/code><\/pre>\n<p>\u0417\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043b\u0443\u0447\u0448\u0435, \u043d\u043e \u0434\u043e \u0437\u0430\u0432\u0435\u0442\u043d\u043e\u0433\u043e \u0447\u0430\u0441\u0430 \u043d\u0430 100\u0413\u0411 \u0435\u0449\u0435 \u043e\u0447\u0435\u043d\u044c \u0434\u0430\u043b\u0435\u043a\u043e. \u0422\u0443\u0442 \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0438\u0437-\u0437\u0430 \u043a\u044d\u0448\u0430 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u0440\u044c\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f +\\-15%<\/p>\n<p>\u041a\u043e\u0434 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 <a href=\"https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/heapsort\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gandjustas\/HugeFileSort\/tree\/heapsort<\/a><\/p>\n<h3>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0424\u0430\u0437\u044b \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f \u0438 \u0441\u043b\u0438\u044f\u043d\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0447\u0442\u0435\u043d\u0438\u044f-\u0437\u0430\u043f\u0438\u0441\u0438, \u0441\u043e\u0437\u0434\u0430\u044e\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0442\u0438\u043f\u0430 string, \u043d\u043e \u0444\u0430\u0437\u0430 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0432 2,5 \u0440\u0430\u0437 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u0430\u043c\u044f\u0442\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u043e\u0434 \u043e\u0442\u043b\u0430\u0434\u0447\u0438\u043a\u043e\u043c \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0441\u0431\u043e\u0440\u043e\u043a \u043c\u0443\u0441\u043e\u0440\u0430.<\/p>\n<p>\u0412\u0441\u0435 \u0434\u0435\u043b\u043e <strong>\u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0436\u0438\u0437\u043d\u0438<\/strong> \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432. \u0412 \u0444\u0430\u0437\u0435 \u0441\u043b\u0438\u044f\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0436\u0438\u0432\u0435\u0442 \u043e\u0442 \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u0447\u0430\u043d\u043a\u0430 \u0434\u043e \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0444\u0430\u0439\u043b. \u041a\u043e\u0433\u0434\u0430 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0438\u0437 \u0447\u0430\u043d\u043a\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u0443\u0436\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043b\u0430\u0441\u044c \u043c\u0443\u0441\u043e\u0440. \u041c\u0443\u0441\u043e\u0440 \u0443\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0432 \u043d\u0443\u043b\u0435\u0432\u043e\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438 \u0441\u0431\u043e\u0440\u0449\u0438\u043a\u0430, \u044d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u043f\u0430\u043c\u044f\u0442\u044c \u043d\u0435 \u0440\u0430\u0441\u0442\u0435\u0442.<\/p>\n<p>\u0412 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0441\u0442\u0440\u043e\u043a \u0436\u0438\u0432\u0443\u0442 \u043e\u0442 \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0434\u043e \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0447\u0430\u043d\u043a. \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441\u0442\u0440\u043e\u043a \u043f\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0431\u043e\u0440\u043e\u043a \u043c\u0443\u0441\u043e\u0440\u0430, \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u043d\u0443\u044e \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0441\u0431\u043e\u0440\u0449\u0438\u043a\u0430 \u0438 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u0435\u043c\u0443\u044e \u043f\u0430\u043c\u044f\u0442\u044c.<\/p>\n<p>\u041c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438 \u0441\u0442\u0440\u043e\u043a \u043d\u0430 \u0444\u0430\u0437\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f. \u041d\u043e \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c! \u041c\u043e\u0436\u043d\u043e<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-344909","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/344909","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=344909"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/344909\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=344909"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=344909"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=344909"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}