{"id":240891,"date":"2014-10-20T11:50:02","date_gmt":"2014-10-20T07:50:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=240891"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=240891","title":{"rendered":"<span class=\"post_title\">AsyncCollections: \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u0430<\/span>"},"content":{"rendered":"<div class=\"content html_format\"> \t\t\t\u0421 \u0434\u0430\u0432\u043d\u0438\u0445 \u0432\u0440\u0435\u043c\u0451\u043d \u044f \u0431\u044b\u043b \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043f\u043e\u043a\u043b\u043e\u043d\u043d\u0438\u043a\u043e\u043c System.Collections.Concurrent \u0438 BlockingCollection \u0432 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438. \u0421\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u044d\u0442\u043e \u0447\u0443\u0434\u043e \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u043e\u0439 \u043c\u044b\u0441\u043b\u0438 \u0432\u044b\u0440\u0443\u0447\u0430\u043b\u043e \u0432 \u0441\u0430\u043c\u044b\u0445 \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u0435\u0439\u0448\u0438\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445 \u2014 \u043d\u0435 \u0441\u0447\u0435\u0441\u0442\u044c.<\/p>\n<p>  \u0421 \u0447\u0443\u0442\u044c \u043c\u0435\u043d\u0435\u0435 \u0434\u0440\u0435\u0432\u043d\u0438\u0445 \u0432\u0440\u0435\u043c\u0451\u043d \u0432 \u043e\u0431\u0438\u0445\u043e\u0434 \u043f\u0440\u043e\u0447\u043d\u043e \u0432\u043e\u0448\u043b\u0438 async\/await. \u041a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b, \u0436\u0438\u0437\u043d\u044c \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u0430, \u043d\u043e \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u043e \u00ab\u043d\u043e\u00bb: \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043c\u0438\u043a\u0441\u043e\u0432\u0430\u0442\u044c \u0441 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u043c \u043a\u043e\u0434\u043e\u043c \u043a\u0430\u043a-\u0442\u043e \u043d\u0435 \u043e\u0447\u0435\u043d\u044c-\u0442\u043e \u0445\u043e\u0447\u0435\u0442\u0441\u044f. \u0410 BlockingCollection, \u043a\u0430\u043a \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u0434\u043e\u0433\u0430\u0434\u0430\u0442\u044c\u0441\u044f (\u0445\u043e\u0442\u044f \u0431\u044b \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f), \u0432 \u0440\u044f\u0434\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u043f\u043e\u0442\u043e\u043a \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442.<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h3>\u041b\u043e\u0436\u043d\u044b\u0439 \u0441\u043b\u0435\u0434: Nito.AsyncEx<\/h3>\n<p>  \u041e\u0434\u043d\u0430\u0436\u0434\u044b \u044f \u043d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <a href=\"https:\/\/github.com\/StephenCleary\/AsyncEx\">Nito.AsyncEx<\/a> \u0437\u0430 \u0430\u0432\u0442\u043e\u0440\u0441\u0442\u0432\u043e\u043c Stephen Cleary, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0448\u0451\u043b\u0441\u044f \u043a\u043b\u0430\u0441\u0441 \u0441 \u0438\u043d\u0442\u0440\u0438\u0433\u0443\u044e\u0449\u0438\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c AsyncCollection. \u041e\u0434\u043d\u0430\u043a\u043e, \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0432 \u0447\u0442\u043e \u0443 \u043d\u0435\u0433\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c, \u044f \u043e\u0441\u0442\u0430\u043b\u0441\u044f \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0435\u0434\u043e\u0443\u043c\u0435\u043d\u0438\u0438: \u0442\u0430\u043c \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f AsyncLock \u0438\u0437 \u044d\u0442\u043e\u0439 \u0436\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043d\u0430\u0432\u0435\u0448\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u0432\u0441\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043d\u0430\u0434 \u043e\u0431\u0451\u0440\u043d\u0443\u0442\u043e\u0439 IProducerConsumerCollection. AsyncLock, \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u044e\u0437\u0430\u0435\u0442 \u0441\u0430\u043c\u044b\u0435 \u043e\u0431\u044b\u043a\u043d\u043e\u0432\u0435\u043d\u043d\u044b\u0435 lock-\u0438 \u0438 \u0442\u043e\u043d\u043a\u0438\u0439 \u0441\u043b\u043e\u0439 \u043c\u0430\u0433\u0438\u0438, \u0440\u0430\u0441\u043f\u0443\u0442\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043d\u0435 \u0432\u043d\u0435\u0437\u0430\u043f\u043d\u043e \u0440\u0430\u0441\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c. \u0414\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u044d\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0435\u043b\u0430\u0435\u0442 \u0442\u043e \u0447\u0442\u043e \u0437\u0430\u044f\u0432\u043b\u0435\u043d\u043e, \u043e\u043d\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0432\u043e\u0440\u043e\u0447\u0435\u043d\u043d\u043e, \u043c\u043e\u043d\u0441\u0442\u0440\u0443\u043e\u0437\u043d\u043e \u0438, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e. \u041d\u0435\u0443\u0436\u0435\u043b\u0438 \u043d\u0435\u043b\u044c\u0437\u044f \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0431\u043e\u043b\u0435\u0435 \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e?<\/p>\n<p>  \u0412\u0441\u0435 \u043c\u044b \u0437\u043d\u0430\u0435\u043c \u0447\u0435\u043c \u0447\u0440\u0435\u0432\u0430\u0442\u044b \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u043c\u044b\u0441\u043b\u0438. Visual Studio, New project\u2026<\/p>\n<h3>AsyncQueue<\/h3>\n<p>  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c\u0441\u044f \u0447\u0442\u043e \u043c\u044b \u0432\u043e\u043e\u0431\u0449\u0435 \u0445\u043e\u0442\u0438\u043c \u043e\u0442 \u043d\u0430\u0448\u0435\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441:<\/p>\n<pre><code>\tpublic interface IAsyncCollection&lt;T&gt;: IEnumerable&lt;T&gt; \t{ \t\tint Count { get; } \t\tvoid Add( T item ); \t\tTask&lt;T&gt; TakeAsync(); \t} <\/code><\/pre>\n<p>  \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u0441\u044f \u043d\u0430 \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0448\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f \u2014 \u044d\u0442\u043e \u043e\u0447\u0435\u0440\u0435\u0434\u044c. \u041f\u043e\u0447\u0435\u043c\u0443 \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0447\u0435\u0440\u0435\u0434\u044c? \u0414\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043f\u043e \u0442\u043e\u0439 \u0436\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u0435, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043f\u043e \u0434\u0435\u0444\u043e\u043b\u0442\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 BlockingCollection.<\/p>\n<p>  \u0414\u0430\u043b\u044c\u0448\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043d\u0430\u043f\u0440\u044f\u0436\u0451\u043d\u043d\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u043c\u044b\u0441\u043b\u0438, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u0430\u044f \u0441 \u043f\u043e\u043f\u044b\u0442\u043a\u043e\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438. \u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u0438\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c 3 \u0448\u0442\u0443\u043a\u0438:<\/p>\n<p>  <b>1.<\/b> \u042d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u043d\u0435\u0442, \u043d\u043e \u0431\u044b\u043b\u0438 \u0432\u044b\u0437\u043e\u0432\u044b TakeAsync(), Task-\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043f\u043e\u044f\u0432\u044f\u0442\u0441\u044f (\u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0438 \u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0442\u0438, \u0434\u0430\u043b\u0435\u0435 \u044f \u0431\u0443\u0434\u0443 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0445 awaiter-\u0430\u043c\u0438). \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435:  <\/p>\n<ul>\n<li>Awaiter-\u044b \u044f\u0432\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0433\u0434\u0435-\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c. \u041d\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0435\u0435 \u2014 ConcurrentQueue.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u0437\u043e\u0432 TakeAsync(), \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 awaiter, \u0437\u0430\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c awaiter-\u043e\u0432.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u0437\u043e\u0432 Add(), \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u0437 awaiter-\u043e\u0432 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0435\u0433\u043e.<\/li>\n<\/ul>\n<p>  <b>2.<\/b> Awaiter-\u043e\u0432 \u043d\u0435\u0442, \u043d\u043e \u0431\u044b\u043b\u0438 \u0432\u044b\u0437\u043e\u0432\u044b Add(). \u0421\u0438\u0442\u0443\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439:  <\/p>\n<ul>\n<li>\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043d\u0443\u0436\u043d\u043e \u0433\u0434\u0435-\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c. \u0413\u0434\u0435? \u0412 ConcurrentQueue, \u0433\u0434\u0435 \u0436\u0435 \u0435\u0449\u0451.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u0437\u043e\u0432 Add(), \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0437\u0430\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u0437\u043e\u0432 TakeAsync(), \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 awaiter, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c, \u0437\u0430\u0431\u0440\u0430\u0432 \u0432\u0435\u0440\u0445\u043d\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438.<\/li>\n<\/ul>\n<p>  <b>3.<\/b> \u041e\u0431\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u2014 \u0438 \u043e\u0447\u0435\u0440\u0435\u0434\u044c awaiter-\u043e\u0432, \u0438 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u2014 \u043f\u0443\u0441\u0442\u044b\u0435. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043b\u0438\u0431\u043e \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 1, \u043b\u0438\u0431\u043e \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 2:  <\/p>\n<ul>\n<li>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u0437\u043e\u0432 Add(), \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0432\u0437\u044f\u0442\u044c \u0434\u043b\u044f \u043d\u0435\u0433\u043e awaiter \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438, \u0442\u0430\u043c \u043f\u0443\u0441\u0442\u043e, \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432&#8230;<\/li>\n<li>\u0412 \u044d\u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u0437\u043e\u0432 TakeAsync(), \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 awaiter, \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0432\u0437\u044f\u0442\u044c \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438, \u0442\u0430\u043c \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043f\u0443\u0441\u0442\u043e, \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c awaiter-\u043e\u0432&#8230;<\/li>\n<li>\u0423\u043f\u0441. \u041c\u044b \u0432\u0441\u0451 \u0441\u043b\u043e\u043c\u0430\u043b\u0438: awaiter \u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u0438\u0434\u044f\u0442 \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u043e\u0447\u0435\u0440\u0435\u0434\u044f\u0445 \u0438 \u0436\u0434\u0443\u0442 \u0434\u0440\u0443\u0433 \u0434\u0440\u0443\u0433\u0430. \u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c?<\/li>\n<\/ul>\n<p>  \u0420\u0430\u0437\u0432\u0435\u0448\u0438\u0432\u0430\u0442\u044c \u043b\u043e\u043a\u0438 \u043d\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f, \u043c\u044b \u043d\u0435 \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0443\u0448\u043b\u0438 \u043e\u0442 \u043d\u0430\u043f\u0438\u0447\u043a\u0430\u043d\u043d\u043e\u0439 \u0438\u043c\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437 Nito.AsyncEx. \u0427\u0442\u043e \u0432 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0434\u0435\u043b\u0430\u044e\u0442 \u0432\u0441\u044f\u043a\u0438\u0435 ConcurrentQueue? \u041f\u043e\u043d\u0438\u043c\u0430\u044e\u0442, \u0447\u0442\u043e \u043f\u0440\u044f\u043c\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u0432 \u0441\u043e\u0441\u0435\u0434\u043d\u0435\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043e\u0442-\u0432\u043e\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f \u0438 \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0435, \u0441\u043e\u0437\u0434\u0430\u044e\u0442 SpinWait \u0438 \u043a\u0440\u0443\u0442\u044f\u0442\u0441\u044f \u0432 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u044d\u0442\u0443 \u0438\u0434\u0435\u044e \u0443 \u043d\u0430\u0441. \u041d\u0443\u0436\u043d\u043e:<\/p>\n<ul>\n<li>\u043f\u043e\u043d\u044f\u0442\u044c \u0432 \u043a\u0430\u043a\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043c\u044b \u043d\u0430\u0445\u043e\u0434\u0438\u043c\u0441\u044f (1 \u0438\u043b\u0438 2)<\/li>\n<li>\u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043e\u0442\u0440\u0430\u043f\u043e\u0440\u0442\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u043c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0441\u0432\u043e\u044e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e, \u0431\u0443\u0434\u044c \u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 awaiter-\u0430 \u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430<\/li>\n<li>\u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043b\u0438\u0431\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c awaiter\/\u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043b\u0438\u0431\u043e \u043f\u043e\u043a\u0440\u0443\u0442\u0438\u0442\u044c\u0441\u044f, \u043f\u043e\u043a\u0430 \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u043b\u043e\u0436\u043d\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u044f\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\/awaiter, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0442\u0443\u0442 \u0436\u0435 \u0437\u0430\u0431\u0435\u0440\u0451\u043c<\/li>\n<\/ul>\n<p>  \u041f\u0435\u0440\u0432\u044b\u0435 \u0434\u0432\u0430 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0447\u0435\u043d\u044c \u0443\u0436 \u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u043a\u043b\u0430\u0441\u0441\u0430 Interlocked; \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0442\u0438\u043f\u0430 \u0431\u0430\u043b\u0430\u043d\u0441\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439: TakeAsync() \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442 \u0431\u0430\u043b\u0430\u043d\u0441 \u043d\u0430 \u0435\u0434\u0438\u043d\u0438\u0446\u0443, Add() \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e \u0436\u0435 \u0435\u0433\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442. \u0418 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0431\u0430\u043b\u0430\u043d\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0435\u0440\u043d\u0451\u0442 Interlocked.Increment\/Interlocked.Decrement, \u043c\u043e\u0436\u043d\u043e \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0433\u0440\u044f\u0434\u0451\u0442 \u043d\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\/awaiter, \u0435\u0449\u0451 \u0434\u043e \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043e\u043d \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u0438. \u0414\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u043e\u043b\u0442\u043e\u0432\u043d\u0438, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0437\u0430\u043a\u043e\u0434\u0438\u0442\u044c \u0432\u0441\u0451 \u0432\u044b\u0448\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435:<\/p>\n<pre><code>\tpublic class AsyncQueue&lt;T&gt;: IAsyncCollection&lt;T&gt; \t{ \t\tprivate ConcurrentQueue&lt;T&gt; _itemQueue = new ConcurrentQueue&lt;T&gt;(); \t\tprivate ConcurrentQueue&lt;TaskCompletionSource&lt;T&gt;&gt; _awaiterQueue = new ConcurrentQueue&lt;TaskCompletionSource&lt;T&gt;&gt;();  \t\t\/\/\t_queueBalance &lt; 0 means there are free awaiters and not enough items. \t\t\/\/\t_queueBalance &gt; 0 means the opposite is true. \t\tprivate long _queueBalance = 0; \t\t \t\tpublic void Add( T item ) \t\t{ \t\t\tlong balanceAfterCurrentItem = Interlocked.Increment( ref _queueBalance );  \t\t\tif ( balanceAfterCurrentItem &gt; 0 ) \t\t\t{ \t\t\t\t\/\/\tItems are dominating, so we can safely add a new item to the queue. \t\t\t\t_itemQueue.Enqueue( item ); \t\t\t} \t\t\telse \t\t\t{ \t\t\t\t\/\/\tThere's at least one awaiter available or being added as we're speaking, so we're giving the item to it.  \t\t\t\tTaskCompletionSource&lt;TItem&gt; awaiter; \t\t\t\tSpinWait spin = new SpinWait();  \t\t\t\twhile ( !_awaiterQueue.TryDequeue( out awaiter ) ) \t\t\t\t\tspin.SpinOnce();  \t\t\t\tawaiter.SetResult( item ); \t\t\t} \t\t}  \t\tpublic Task&lt;T&gt; TakeAsync() \t\t{ \t\t\tlong balanceAfterCurrentAwaiter = Interlocked.Decrement( ref _queueBalance );  \t\t\tif ( balanceAfterCurrentAwaiter &lt; 0 ) \t\t\t{ \t\t\t\t\/\/\tAwaiters are dominating, so we can safely add a new awaiter to the queue.  \t\t\t\tvar taskSource = new TaskCompletionSource&lt;TItem&gt;(); \t\t\t\t_awaiterQueue.Enqueue( taskSource ); \t\t\t\treturn taskSource.Task; \t\t\t} \t\t\telse \t\t\t{ \t\t\t\t\/\/\tThere's at least one item available or being added, so we're returning it directly.  \t\t\t\tT item; \t\t\t\tSpinWait spin = new SpinWait();  \t\t\t\twhile ( !_itemQueue.TryTake( out item ) ) \t\t\t\t\tspin.SpinOnce();  \t\t\t\treturn Task.FromResult( item ); \t\t\t} \t\t} \t} <\/code><\/pre>\n<p>  \u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c, \u0441 \u0443\u0434\u0438\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u043e\u043d\u043e \u0432\u0440\u043e\u0434\u0435 \u0431\u044b \u0434\u0430\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u041f\u043e\u0431\u0435\u0434\u0430? \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0434\u0430, \u0441 \u0434\u0440\u0443\u0433\u043e\u0439, \u0440\u0430\u0437\u043e\u0433\u043d\u0430\u0432\u0448\u0438\u0439\u0441\u044f \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u043e\u0440\u044b\u0432 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u2026<\/p>\n<h4>\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 (\u0438 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c) \u043f\u043b\u044e\u0448\u043a\u0438<\/h4>\n<p>  \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430 \u0442\u043e \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c. \u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 Add(), \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 TakeAsync()\u2026 \u0421\u0442\u043e\u043f, \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0431\u0435\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0435\u0433\u043e \u043e\u0442\u043c\u0435\u043d\u044b? \u041d\u0435\u043f\u043e\u0440\u044f\u0434\u043e\u043a. \u0418\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c.<\/p>\n<p>  \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435 CancellationToken-\u0430 \u043d\u0443\u0436\u043d\u043e \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0442\u0430\u0441\u043a:<\/p>\n<pre><code>\t\tpublic Task&lt;TItem&gt; TakeAsync( CancellationToken cancellationToken ) \t\t{ \t\t\t\/\/\t...  \t\t\tif ( balanceAfterCurrentAwaiter &lt; 0 ) \t\t\t{ \t\t\t\tvar taskSource = new TaskCompletionSource&lt;TItem&gt;(); \t\t\t\t_awaiterQueue.Enqueue( taskSource );  \t\t\t\tcancellationToken.Register( \t\t\t\t\tstate =&gt; \t\t\t\t\t{ \t\t\t\t\t\tTaskCompletionSource&lt;T&gt; awaiter = state as TaskCompletionSource&lt;T&gt;; \t\t\t\t\t\tawaiter.TrySetCanceled(); \t\t\t\t\t}, \t\t\t\t\ttaskSource, \t\t\t\t\tuseSynchronizationContext : false );  \t\t\t\treturn taskSource.Task; \t\t\t} \t\t\telse \t\t\t{ \t\t\t\t\/\/\t... \t\t\t} \t\t} <\/code><\/pre>\n<p>  \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0432\u044b\u043a\u043e\u0432\u044b\u0440\u044f\u0442\u044c \u043e\u0442\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0439 awaiter \u043e\u0442\u043a\u0443\u0434\u0430-\u0442\u043e \u0438\u0437 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u044b \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043c\u044b \u044f\u0432\u043d\u043e \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0443\u0447\u0438\u0442\u044c Add() \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043e\u043d\u044b\u0439 \u043e\u0442\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0439 awaiter. \u0411\u0430\u043b\u0430\u043d\u0441 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432\u043e\u043b\u0448\u0435\u0431\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438:<\/p>\n<pre><code>\t\tprivate bool TryAdd( TItem item ) \t\t{ \t\t\tlong balanceAfterCurrentItem = Interlocked.Increment( ref _queueBalance );  \t\t\tif ( balanceAfterCurrentItem &gt; 0 ) \t\t\t{ \t\t\t\t_itemQueue.Enqueue( item ); \t\t\t\treturn true; \t\t\t} \t\t\telse \t\t\t{ \t\t\t\tTaskCompletionSource&lt;T&gt; awaiter; \t\t\t\tSpinWait spin = new SpinWait();  \t\t\t\twhile ( !_awaiterQueue.TryDequeue( out awaiter ) ) \t\t\t\t\tspin.SpinOnce();  \t\t\t\t\/\/\tReturns false if the cancellation occurred earlier. \t\t\t\treturn awaiter.TrySetResult( item ); \t\t\t} \t\t}  \t\tpublic void Add( TItem item ) \t\t{ \t\t\twhile ( !TryAdd( item ) ) ; \t\t} <\/code><\/pre>\n<p>  \u0412-\u0442\u0440\u0435\u0442\u044c\u0438\u0445, \u0441\u0442\u0430\u0440\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 TakeAsync() (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0435\u0437 CancellationToken) \u0432\u043e\u043e\u0431\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0432 extension \u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443 IAsyncCollection:<\/p>\n<pre><code>\tpublic interface IAsyncCollection&lt;T&gt;: IEnumerable&lt;T&gt; \t{ \t\tint Count { get; } \t\tvoid Add( T item ); \t\tTask&lt;T&gt; TakeAsync( CancellationToken cancellationToken ); \t}  \tpublic static class AsyncCollectionExtensions \t{ \t\tpublic static Task&lt;T&gt; TakeAsync&lt;T&gt;( this IAsyncCollection&lt;T&gt; collection ) \t\t{ \t\t\treturn collection.TakeAsync( CancellationToken.None ); \t\t} \t} <\/code><\/pre>\n<p>  \u041a\u0441\u0442\u0430\u0442\u0438, \u043f\u0440\u043e IAsyncCollection. \u0415\u0441\u043b\u0438 \u043f\u0440\u0438\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c\u0441\u044f, \u0442\u043e \u043d\u0430\u0448\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f AsyncQueue \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u043d\u0430 \u0431\u044b\u0442\u044c \u043f\u0440\u0438\u0431\u0438\u0442\u0430 \u0433\u0432\u043e\u0437\u0434\u044f\u043c\u0438 \u043a ConcurrentQueue, \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u0434\u043e\u0439\u0434\u0451\u0442 \u043b\u044e\u0431\u0430\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u0430\u044f IProducerConsumerCollection. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, ConcurrentStack. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code>\tpublic class AsyncCollection&lt;TItem, TItemQueue&gt;: IAsyncCollection&lt;TItem&gt; \t\twhere TItemQueue: IProducerConsumerCollection&lt;TItem&gt;, new() \t{ \t\tprivate TItemQueue _itemQueue = new TItemQueue(); \t\tprivate ConcurrentQueue&lt;TaskCompletionSource&lt;TItem&gt;&gt; _awaiterQueue = new ConcurrentQueue&lt;TaskCompletionSource&lt;TItem&gt;&gt;();  \t\t\/\/\t... \t}  \tpublic class AsyncQueue&lt;T&gt;: AsyncCollection&lt;T, ConcurrentQueue&lt;T&gt;&gt; \t{ \t}  \tpublic class AsyncStack&lt;T&gt;: AsyncCollection&lt;T, ConcurrentStack&lt;T&gt;&gt; \t{ \t} <\/code><\/pre>\n<p>  \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043d\u0435 \u043f\u043b\u043e\u0434\u0438\u0442\u044c type parameter-\u044b, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c IProducerConsumerCollection \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435, \u043d\u043e \u0432\u043e\u0442 \u0431\u0435\u0434\u0430: \u043d\u0430\u043c \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0434\u0441\u0443\u043d\u0443\u0442\u044c \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0443\u0436\u0435 \u0441\u0441\u044b\u043b\u0430\u044e\u0442\u0441\u044f \u0441\u043d\u0430\u0440\u0443\u0436\u0438 \u0438 \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0433\u0443\u0442 \u0441\u043d\u0430\u0440\u0443\u0436\u0438 \u0436\u0435 \u043f\u043e\u043d\u0430\u043f\u0438\u0445\u0430\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 (\u0438\u043b\u0438, \u0447\u0442\u043e \u0435\u0449\u0451 \u0445\u0443\u0436\u0435, \u0437\u0430\u0431\u0440\u0430\u0442\u044c \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0448\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432), \u0442\u0430\u043c \u0441\u0430\u043c\u044b\u043c \u0440\u0430\u0437\u0440\u0443\u0448\u0438\u0432 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044e \u043c\u0435\u0436\u0434\u0443 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0438 \u0437\u0430\u043f\u043e\u043c\u043d\u0435\u043d\u043d\u044b\u043c \u0431\u0430\u043b\u0430\u043d\u0441\u043e\u043c. \u0421 factory method \u0442\u0430 \u0436\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u0442\u0430\u043a \u0447\u0442\u043e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0430\u043c\u0438\u043c.<\/p>\n<h4>\u0411\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0438!<\/h4>\n<p>  \u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u043c\u0435\u0440\u0438\u0442\u044c \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0448\u0435\u0433\u043e \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u0430. \u0414\u043b\u044f \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u043e\u0432 \u0435\u0441\u0442\u044c \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/www.nuget.org\/packages\/BenchmarkDotNet\/\">BenchmarkDotNet<\/a>, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u0439 \u043a\u0443\u0447\u0443 \u043c\u0435\u043b\u043a\u0438\u0445 \u0434\u0435\u0442\u0430\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u043f\u0440\u043e\u0433\u043e\u043d\u0435 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u043e\u0432, \u0442\u0430\u043a \u0447\u0442\u043e \u0435\u0433\u043e \u0438 \u0437\u0430\u044e\u0437\u0430\u0435\u043c. \u041e\u0431\u0449\u0430\u044f \u0438\u0434\u0435\u044f \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c:<\/p>\n<pre><code>\tclass AsyncQueueBenchmark \t{ \t\tprivate const int _consumerThreadCount = 3; \t\tprivate const int _producerThreadCount = 3; \t\tprivate const int _itemsAddedPerThread = 10000; \t\tprivate const int _itemsAddedTotal = _producerThreadCount * _itemsAddedPerThread; \t\t \t\tprivate IAsyncCollection&lt;int&gt; _currentQueue; \t\tprivate CancellationTokenSource _cancelSource; \t\tprivate int _itemsTaken;  \t\t\/\/ \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u0440\u044f\u0442\u044c\u0441\u044f \t\tprivate void DdosCurrentQueue() \t\t{ \t\t\t_consumerTasks = Enumerable.Range( 0, _consumerThreadCount ) \t\t\t\t.Select( _ =&gt; Task.Run( () =&gt; RunConsumerAsync() ) ) \t\t\t\t.ToArray();  \t\t\t_producerTasks = Enumerable.Range( 0, _producerThreadCount ) \t\t\t\t.Select( _ =&gt; Task.Run( () =&gt; RunProducer() ) ) \t\t\t\t.ToArray();  \t\t\tTask.WaitAll( _producerTasks ); \t\t\tTask.WaitAll( _consumerTasks ); \t\t}  \t\tprivate async Task RunConsumerAsync() \t\t{ \t\t\ttry \t\t\t{ \t\t\t\tCancellationToken cancelToken = _cancelSource.Token;  \t\t\t\twhile ( _itemsTaken &lt; _itemsAddedTotal && !cancelToken.IsCancellationRequested ) \t\t\t\t{ \t\t\t\t\tint item = await _currentQueue.TakeAsync( cancelToken ); \t\t\t\t\tint itemsTakenLocal = Interlocked.Increment( ref _itemsTaken );  \t\t\t\t\tif ( itemsTakenLocal &gt;= _itemsAddedTotal ) \t\t\t\t\t{ \t\t\t\t\t\t_cancelSource.Cancel(); \t\t\t\t\t\tbreak; \t\t\t\t\t} \t\t\t\t} \t\t\t} \t\t\tcatch ( OperationCanceledException ) \t\t\t{ \t\t\t} \t\t}  \t\tprivate void RunProducer() \t\t{ \t\t\tfor ( int i = 0; i &lt; _itemsAddedPerThread; i++ ) \t\t\t{ \t\t\t\tint item = 42; \t\t\t\t_currentQueue.Add( item ); \t\t\t} \t\t} <\/code><\/pre>\n<p>  \u0422.\u0435. \u043f\u0440\u043e\u0441\u0442\u043e \u0431\u0435\u0440\u0451\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043f\u0430\u0447\u043a\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0444\u0438\u0433\u0430\u0447\u0438\u043c \u0438\u0445 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043a\u043e\u0432, \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0436\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u044d\u0442\u0443 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0440\u0430\u0437\u0433\u0440\u0435\u0431\u0430\u0435\u043c, \u0437\u0430\u0441\u0435\u043a\u0430\u0435\u043c \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u044d\u0442\u043e \u0443\u0439\u0434\u0451\u0442. \u041f\u043e\u0434\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0440\u0430\u0437\u043d\u044b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 IAsyncCollection, \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c. \u0412 \u0437\u0430\u0431\u0435\u0433\u0435 \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u044e\u0442:<\/p>\n<p>  <b>1.<\/b> \u0421\u0432\u0435\u0436\u0435\u043d\u0430\u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u0435\u043d\u043d\u044b\u0439 AsyncQueue<br \/>  <b>2.<\/b> Nito.AsyncEx.AsyncCollection \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0432\u0438\u0434\u0435:<\/p>\n<pre><code>\tclass NitoAsyncCollectionAdapter&lt;T&gt;: IAsyncCollection&lt;T&gt; \t{ \t\tprivate Nito.AsyncEx.AsyncCollection&lt;T&gt; _collection;  \t\tpublic NitoAsyncCollectionAdapter() \t\t{ \t\t\t_collection = new Nito.AsyncEx.AsyncCollection&lt;T&gt;(); \t\t}  \t\t#region IAsyncCollection&lt;T&gt; Members  \t\tpublic void Add( T item ) \t\t{ \t\t\t_collection.Add( item ); \t\t}  \t\tpublic Task&lt;T&gt; TakeAsync( System.Threading.CancellationToken cancellationToken ) \t\t{ \t\t\treturn _collection.TakeAsync( cancellationToken ); \t\t}  \t\t#endregion \t} <\/code><\/pre>\n<p>  <b>3.<\/b> BlockingCollection (\u043d\u0443 \u043a\u0430\u043a \u0436\u0435 \u043d\u0435 \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0441 \u043d\u0435\u0439) \u0432 \u0432\u0438\u0434\u0435:<\/p>\n<pre><code>\tclass BlockingCollectionAdapter&lt;T&gt;: IAsyncCollection&lt;T&gt; \t{ \t\tprivate BlockingCollection&lt;T&gt; _collection;  \t\tpublic BlockingCollectionAdapter() \t\t{ \t\t\t_collection = new BlockingCollection&lt;T&gt;(); \t\t}  \t\t#region IAsyncCollection&lt;T&gt; Members  \t\tpublic void Add( T item ) \t\t{ \t\t\t_collection.Add( item ); \t\t}  \t\tpublic Task&lt;T&gt; TakeAsync( System.Threading.CancellationToken cancellationToken ) \t\t{ \t\t\tT item = _collection.Take( cancellationToken ); \t\t\treturn Task.FromResult( item ); \t\t}  \t\t#endregion \t} <\/code><\/pre>\n<p>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b:  <\/p>\n<pre> HellBrick.AsyncCollections.AsyncQueue :  1ms | Stats: MedianTicks= 3368, MedianMs= 1, Error=06.34% Nito.AsyncEx.AsyncCollection          : 12ms | Stats: MedianTicks=40503, MedianMs=12, Error=31.36% System.Concurrent.BlockingCollection  :  2ms | Stats: MedianTicks= 7222, MedianMs= 2, Error=38.82% <\/pre>\n<p>  \u0418\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u0430\u044f \u043e\u0446\u0435\u043d\u043a\u0430 Nito.AsyncEx.AsyncCollection \u043d\u0435 \u043f\u043e\u0434\u0432\u0435\u043b\u0430: \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043c\u043e\u043d\u0441\u0442\u0440\u0443\u043e\u0437\u043d\u0430\u044f \u0442\u043e\u0440\u043c\u043e\u0437\u043d\u0443\u0442\u0430\u044f \u0445\u0440\u0435\u043d\u044c. \u041d\u043e \u0441\u0430\u043c\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435: \u043d\u0430\u043c \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0431\u043e\u0433\u043d\u0430\u0442\u044c BlockingCollection \u043f\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0432. Win! \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u0440\u0442\u0438\u043a \u0438\u043b\u0438 \u043b\u044e\u0431\u0443\u044e \u0434\u0440\u0443\u0433\u0443\u044e \u0431\u043e\u043d\u0443\u0441\u043d\u0443\u044e \u0432\u043a\u0443\u0441\u043d\u044f\u0448\u043a\u0443 \u0438 \u0435\u0434\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<h3>AsyncBatchQueue<\/h3>\n<p>  \u041c\u043d\u0435 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0432\u0440\u0430\u043f\u043f\u0435\u0440 \u043d\u0430\u0434 BlockingCollection, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b \u043d\u0430 \u0432\u0445\u043e\u0434 \u043e\u0434\u0438\u043d\u043e\u0447\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0438 \u043e\u0442\u0434\u0430\u0432\u0430\u043b \u0438\u0445 \u043f\u0430\u0447\u043a\u0430\u043c\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0435\u0441\u043b\u0438 \u0437\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0443\u0436\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0442\u0430\u043a \u0438 \u043d\u0435 \u043d\u0430\u0431\u0440\u0430\u043b\u043e\u0441\u044c, \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b \u0442\u0430\u0439\u043c\u0435\u0440 \u0438 \u0434\u0435\u043b\u0430\u043b \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 flush \u0442\u043e\u0433\u043e \u0447\u0442\u043e \u043c\u044b \u0443\u0441\u043f\u0435\u043b\u0438 \u043d\u0430\u0431\u0440\u0430\u0442\u044c. \u041a\u0442\u043e \u0445\u043e\u0447\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0439 \u0448\u0442\u0443\u043a\u0438? \u042f \u0445\u043e\u0447\u0443.<\/p>\n<p>  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0431\u043e\u0439\u0434\u0451\u043c\u0441\u044f \u0431\u0435\u0437 \u0442\u0430\u0439\u043c\u0435\u0440\u0430 \u0438 \u0440\u0443\u0447\u043d\u043e\u0433\u043e flush-\u0430. \u0421\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u0447\u043a\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 \u043d\u0430\u0448\u0435\u0439 \u043d\u043e\u0432\u043e\u0439 AsyncQueue:<\/p>\n<pre><code>\tpublic class AsyncBatchQueue&lt;T&gt; \t{ \t\tprivate int _batchSize; \t\tprivate Batch _currentBatch; \t\tprivate AsyncQueue&lt;IReadOnlyList&lt;T&gt;&gt; _batchQueue = new AsyncQueue&lt;IReadOnlyList&lt;T&gt;&gt;();  \t\tpublic AsyncBatchQueue( int batchSize ) \t\t{ \t\t\t_batchSize = batchSize; \t\t\t_currentBatch = new Batch( this ); \t\t}  \t\tpublic void Add( T item ) \t\t{ \t\t\tSpinWait spin = new SpinWait();  \t\t\twhile ( !_currentBatch.TryAdd( item ) ) \t\t\t\tspin.SpinOnce(); \t\t}  \t\tpublic Task&lt;IReadOnlyList&lt;T&gt;&gt; TakeAsync( CancellationToken cancellationToken ) \t\t{ \t\t\treturn _batchQueue.TakeAsync( cancellationToken ); \t\t}  \t\tprivate class Batch: IReadOnlyList&lt;T&gt; \t\t{ \t\t\tprivate AsyncBatchQueue&lt;T&gt; _queue; \t\t\t\/\/\t?  \t\t\tpublic Batch( AsyncBatchQueue&lt;T&gt; queue ) \t\t\t{ \t\t\t\t_queue = queue; \t\t\t}  \t\t\tpublic bool TryAdd( T item ) \t\t\t{ \t\t\t\t\/\/\t? \t\t\t} \t\t} \t} <\/code><\/pre>\n<p>  \u0427\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442: \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 Add \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0434\u043e\u0434\u0431\u0430\u0432\u0438\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 batch \u0438, \u0435\u0441\u043b\u0438 \u043c\u044b \u0435\u0433\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u043b\u0438, \u0437\u0430-flush-\u0438\u0442\u044c \u0435\u0433\u043e \u0432 _batchQueue. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432\u043f\u043e\u043b\u043d\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f, \u043a\u043e\u0433\u0434\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u043d\u0430\u0441 \u043e\u043f\u0435\u0440\u0435\u0434\u0438\u043b, \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c\/flush-\u0435\u043c, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0435\u0449\u0451 \u043d\u0435 \u0443\u0441\u043f\u0435\u043b \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 _currentBatch \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 (\u043f\u0443\u0441\u0442\u043e\u0439) batch. \u041e\u0442\u0441\u044e\u0434\u0430 \u0441\u0442\u0430\u0440\u044b\u0439 \u0434\u043e\u0431\u0440\u044b\u0439 SpinWait.<\/p>\n<p>  \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u043c\u0430\u0433\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432 nested \u043a\u043b\u0430\u0441\u0441\u0435 Batch, \u0438\u0434\u0435\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0430\u043c\u044b\u043c \u043d\u0430\u0433\u043b\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0430 \u0438\u0437 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 ConcurrentQueue (\u043a\u0441\u0442\u0430\u0442\u0438, \u0435\u0441\u043b\u0438 \u043a\u0442\u043e \u043d\u0435 \u0447\u0438\u0442\u0430\u043b \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f: \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0433\u043e). \u0418\u0434\u0435\u044f \u044d\u0442\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c: <\/p>\n<ul>\n<li>\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0445\u0440\u0430\u043d\u0438\u043c \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u043c \u043c\u0430\u0441\u0441\u0438\u0432\u0435, \u0431\u043b\u0430\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440 \u043c\u044b \u0437\u043d\u0430\u0435\u043c \u0437\u0430\u0440\u0430\u043d\u0435\u0435<\/li>\n<li>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441 concurrency \u0440\u0435\u0448\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Interlocked.Increment \u043f\u043e\u043b\u044f, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u043d\u0434\u0435\u043a\u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435\u0433\u043e \u0432\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430<\/li>\n<li>\u0415\u0441\u043b\u0438 \u043f\u043e\u0442\u043e\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u043b \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0441\u043b\u043e\u0442 \u043c\u0430\u0441\u0441\u0438\u0432\u0430, \u0442\u043e \u043d\u0430 \u043d\u0435\u0433\u043e [\u043f\u043e\u0442\u043e\u043a, \u043d\u0435 \u0441\u043b\u043e\u0442] \u0432\u043e\u0437\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044e flush-\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e batch-\u0430<\/li>\n<li>\u0415\u0441\u043b\u0438 \u043f\u043e\u0442\u043e\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u043b \u0441\u043b\u043e\u0442, \u0432\u044b\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u0437\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u043c\u0430\u0441\u0441\u0438\u0432\u0430, \u0442\u043e \u043d\u0430\u043c \u043d\u0435 \u043f\u043e\u0432\u0435\u0437\u043b\u043e: \u044d\u0442\u043e\u0442 batch \u0443\u0436\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d \u0438 \u043f\u043e\u0442\u043e\u043a\u0443 \u043d\u0443\u0436\u043d\u043e \u043a\u0440\u0443\u0442\u0438\u0442\u044c\u0441\u044f \u0432 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e<\/li>\n<\/ul>\n<p>  \u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u044d\u0442\u043e \u043a\u0430\u043a-\u0442\u043e \u0442\u0430\u043a. (\u041e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u043e, \u043a\u043e\u0434 \u043f\u043e\u043a\u0430 \u043d\u0435\u0436\u0438\u0437\u043d\u0435\u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d! \u0427\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u043e\u0447\u0435\u043c\u0443.)<\/p>\n<pre><code>\t\tprivate class Batch: IReadOnlyList&lt;T&gt; \t\t{ \t\t\tprivate AsyncBatchQueue&lt;T&gt; _queue; \t\t\tprivate T[] _items; \t\t\tprivate int _lastReservationIndex = -1; \t\t\tprivate int _count = -1;  \t\t\tpublic Batch( AsyncBatchQueue&lt;T&gt; queue ) \t\t\t{ \t\t\t\t_queue = queue; \t\t\t\t_items = new T[ _queue._batchSize ]; \t\t\t}  \t\t\tpublic bool TryAdd( T item ) \t\t\t{ \t\t\t\tint index = Interlocked.Increment( ref _lastReservationIndex );  \t\t\t\t\/\/\tThe following is true if someone has beaten us to the last slot and we have to wait until the next batch comes along. \t\t\t\tif ( index &gt;= _queue._batchSize ) \t\t\t\t\treturn false;  \t\t\t\t\/\/\tThe following is true if we've taken the last slot, which means we're obligated to flush the current batch and create a new one. \t\t\t\tif ( index == _queue._batchSize - 1 ) \t\t\t\t\tFlushInternal( _queue._batchSize );  \t\t\t\t_items[ index ] = item; \t\t\t\treturn true; \t\t\t}  \t\t\tprivate void FlushInternal( int count ) \t\t\t{ \t\t\t\t_count = count; \t\t\t\t_queue._currentBatch = new Batch( _queue ); \t\t\t\t_queue._batchQueue.Add( this ); \t\t\t} \t\t} <\/code><\/pre>\n<p>  \u0414\u0430\u043b\u044c\u0448\u0435 \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0432\u0441\u0451 \u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c IReadOnlyList. \u0422\u0443\u0442 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u0435\u0442 \u043e\u0434\u0438\u043d \u043d\u044e\u0430\u043d\u0441: \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0437\u0430-flush-\u0438\u043b\u0438 batch, \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u041f\u043e\u0442\u043e\u043a, \u0441\u0445\u0432\u0430\u0442\u0438\u0432\u0448\u0438\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u043c\u043e\u0433 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u0435\u0435. \u041d\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0435: \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043b\u043e\u0442\u0430 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0444\u043b\u0430\u0433, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0438\u0439, \u043c\u043e\u0436\u043d\u043e \u043b\u0438 \u0447\u0438\u0442\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435.<\/p>\n<pre><code>\t\tprivate class Batch: IReadOnlyList&lt;T&gt; \t\t{ \t\t\t\/\/\t... \t\t\tprivate bool[] _finalizationFlags;  \t\t\tpublic Batch( AsyncBatchQueue&lt;T&gt; queue ) \t\t\t{ \t\t\t\t\/\/\t... \t\t\t\t_finalizationFlags = new bool[ _queue._batchSize ]; \t\t\t}  \t\t\tpublic bool TryAdd( T item ) \t\t\t{ \t\t\t\t\/\/\t... \t\t\t\t_items[ index ] = item; \t\t\t\t_finalizationFlags[ index ] = true;  \t\t\t\treturn true; \t\t\t}  \t\t\tpublic T this[ int index ] \t\t\t{ \t\t\t\tget \t\t\t\t{ \t\t\t\t\tif ( index &gt;= _count ) \t\t\t\t\t\tthrow new IndexOutOfRangeException();  \t\t\t\t\treturn GetItemWithoutValidation( index ); \t\t\t\t} \t\t\t}  \t\t\tprivate T GetItemWithoutValidation( int index ) \t\t\t{ \t\t\t\tSpinWait spin = new SpinWait(); \t\t\t\twhile ( !_finalizationFlags[ index ] ) \t\t\t\t\tspin.SpinOnce();  \t\t\t\treturn _items[ index ]; \t\t\t}  \t\t\t\/\/\t... \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 GetItemWithoutValidation \t\t} <\/code><\/pre>\n<p>  \u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u043c\u0430\u0433\u0438\u044f. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432 \u043a\u043e\u0434\u0435 \u0435\u0441\u0442\u044c \u043a\u0443\u0447\u0430 \u043c\u0435\u0441\u0442, \u0433\u0434\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0441 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u043e\u043c \u043c\u043e\u0433\u0443\u0442 \u0432\u0441\u0451 \u0438\u0441\u043f\u043e\u0440\u0442\u0438\u0442\u044c, \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u043a\u044d\u0448\u0438\u0440\u0443\u044f \u0442\u043e, \u0447\u0442\u043e \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u043b\u044c\u0437\u044f.<\/p>\n<p>  <b>1.<\/b> \u0412 AsyncBatchCollection.Add() \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 _currentBatch \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d\u043e \u043e\u0434\u043d\u0430\u0436\u0434\u044b \u0438 \u0437\u0430\u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043e, \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0447\u0435\u0433\u043e, \u0435\u0441\u043b\u0438 batch \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u043b\u0441\u044f, \u043f\u043e\u0442\u043e\u043a \u0431\u0443\u0434\u0435\u0442 \u043a\u0440\u0443\u0442\u0438\u0442\u044c\u0441\u044f \u0432\u0435\u0447\u043d\u043e. volatile \u0441\u043f\u0435\u0448\u0438\u0442 \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c:<\/p>\n<pre><code>\tpublic class AsyncBatchQueue&lt;T&gt; \t{ \t\t\/\/\t... \t\tprivate volatile Batch _currentBatch; \t\t\/\/\t... \t} <\/code><\/pre>\n<p>  <b>2.<\/b> \u0412 \u043c\u0435\u0442\u043e\u0434\u0435 FlushInternal() batch \u043c\u043e\u0436\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u0432 \u0432\u044b\u0445\u043e\u0434\u043d\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0434\u043e \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u043f\u043e\u043b\u0435 _count. \u0412\u0442\u044b\u043a\u0430\u0435\u043c full fence:<\/p>\n<pre><code>\tprivate void FlushInternal( int count ) \t{ \t\t_count = count; \t\t_queue._currentBatch = new Batch( _queue );  \t\t\/\/\tThe full fence ensures that the current batch will never be added to the queue before _count is set. \t\tThread.MemoryBarrier();  \t\t_queue._batchQueue.Add( this ); \t} <\/code><\/pre>\n<p>  <b>3.<\/b> \u0412 \u043c\u0435\u0442\u043e\u0434\u0435 TryAdd \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 _items[ index ] \u0438 _finalizationFlags[ index ] \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043c\u0435\u0441\u0442\u0430\u043c\u0438. \u041e\u043f\u044f\u0442\u044c \u0432\u0442\u044b\u043a\u0430\u0435\u043c full fence:<\/p>\n<pre><code>\tpublic bool TryAdd( T item ) \t{ \t\t\/\/\t...  \t\t\/\/\tThe full fence prevents setting finalization flag before the actual item value is written. \t\t_items[ index ] = item; \t\tThread.MemoryBarrier(); \t\t_finalizationFlags[ index ] = true;  \t\treturn true; \t} <\/code><\/pre>\n<p>  <b>4.<\/b> \u041e\u0431\u0440\u0430\u0442\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 (\u0447\u0442\u0435\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u0435\u0440\u0435\u0434 \u0444\u043b\u0430\u0433\u043e\u043c) \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u0432 GetItemWithoutValidation. \u0412\u0442\u044b\u043a\u0430\u0435\u043c \u0441\u0430\u043c\u0438-\u0437\u043d\u0430\u0435\u0442\u0435-\u0447\u0442\u043e:<\/p>\n<pre><code>\tprivate T GetItemWithoutValidation( int index ) \t{ \t\tSpinWait spin = new SpinWait(); \t\twhile ( !_finalizationFlags[ index ] ) \t\t\tspin.SpinOnce();  \t\t\/\/\tThe full fence prevents reading item value before finalization flag is set. \t\tThread.MemoryBarrier(); \t\treturn _items[ index ]; \t} <\/code><\/pre>\n<p>  <b>5.<\/b> \u0412\u0441\u0451 \u0432 \u0442\u043e\u043c \u0436\u0435 \u043c\u0435\u0442\u043e\u0434\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 _finalizationFlags[ index ] \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043e, \u0438\u0437-\u0437\u0430 \u0447\u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043a \u0431\u0443\u0434\u0435\u0442 \u043a\u0440\u0443\u0442\u0438\u0442\u044c\u0441\u044f \u0432\u0435\u0447\u043d\u043e. \u041e\u0431\u044b\u0447\u043d\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0432\u0435\u0448\u0438\u0432\u0430\u043d\u0438\u0435\u043c \u043d\u0430 \u043f\u043e\u043b\u0435 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 volatile, \u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u043d\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0443 \u0432\u044b \u043f\u043e\u043d\u044f\u043b\u0438:<\/p>\n<pre><code>\tprivate T GetItemWithoutValidation( int index ) \t{ \t\tSpinWait spin = new SpinWait(); \t\twhile ( !_finalizationFlags[ index ] ) \t\t{ \t\t\tspin.SpinOnce();  \t\t\t\/\/\tThe full fence prevents caching any part of _finalizationFlags[ index ] expression. \t\t\tThread.MemoryBarrier(); \t\t}  \t\t\/\/\t... \t} <\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0417\u0434\u0435\u0441\u044c, \u043a\u0441\u0442\u0430\u0442\u0438, \u0441\u0442\u043e\u0438\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/b><\/p>\n<div class=\"spoiler_text\">\u0412 ConcurrentQueue \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f <a href=\"http:\/\/referencesource.microsoft.com\/#mscorlib\/system\/Collections\/Concurrent\/ConcurrentQueue.cs#658\">\u0432\u0435\u0441\u044c\u043c\u0430 \u043d\u0435\u043e\u0431\u044b\u0447\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c<\/a>:  <\/p>\n<pre><code>\tinternal volatile VolatileBool[] m_state;  \tstruct VolatileBool \t{ \t\tpublic VolatileBool(bool value) \t\t{ \t\t\tm_value = value; \t\t} \t\tpublic volatile bool m_value; \t} <\/code><\/pre>\n<p>  \u0415\u0441\u043b\u0438 \u0431\u044b VolatileBool \u0431\u044b\u043b \u043a\u043b\u0430\u0441\u0441\u043e\u043c \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u0432\u0441\u0451 \u0431\u044b\u043b\u043e \u0431\u044b \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e: \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 VolatileBool \u0433\u0434\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u0437\u0430\u043a\u044d\u0448\u0438\u0440\u0443\u044e\u0442, \u0447\u0442\u0435\u043d\u0438\u0435 volatile m_value \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044f. \u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e\u0442 \u0444\u0438\u043d\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u043e \u0438\u0434\u0435\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u043e \u0431\u044b\u0442\u044c \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b\u0437\u043e\u0432\u0430 m_state[ index ], \u044f \u0442\u0430\u043a \u0438 \u043d\u0435 \u043f\u043e\u043d\u044f\u043b.<\/div>\n<\/div>\n<p>  \u0412\u0440\u043e\u0434\u0435 \u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u043c\u0435\u0441\u0442\u0430 \u043d\u0430 \u044d\u0442\u043e\u043c \u043a\u043e\u043d\u0447\u0438\u043b\u0438\u0441\u044c \u0438 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0434\u043e\u043b\u0436\u0435\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c (\u043f\u043e \u043a\u0440\u0430\u0439\u043d\u0435\u0439 \u043c\u0435\u0440\u0435, \u043c\u043d\u0435 \u0438\u0441\u043a\u0440\u0435\u043d\u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0432 \u044d\u0442\u043e \u0432\u0435\u0440\u0438\u0442\u044c).<\/p>\n<h4>\u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043a\u043e\u0440\u044f\u0447\u0438\u0432\u0430\u0435\u043c \u0442\u0430\u0439\u043c\u0435\u0440<\/h4>\n<p>  \u0412\u0441\u0451 \u0432\u0440\u043e\u0434\u0435 \u0431\u044b \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u043d\u043e \u0435\u0441\u0442\u044c \u043e\u0434\u0438\u043d (\u0443\u0436\u0435 \u043d\u0435 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0439 \u0441 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c\u044e) \u043d\u044e\u0430\u043d\u0441: \u0435\u0441\u043b\u0438 \u0432 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e \u0434\u043e\u0431\u0430\u0432\u044f\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043d\u0435 \u043a\u0440\u0430\u0442\u043d\u043e\u0435 batchSize, \u0442\u043e \u043e\u0441\u0442\u0430\u0442\u043e\u043a \u043c\u044b \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0443\u0432\u0438\u0434\u0438\u043c. \u041d\u0443\u0436\u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u043b\u0430\u0442\u044c flush \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0430 \u043b\u0443\u0447\u0448\u0435 \u2014 \u043f\u043e \u0442\u0430\u0439\u043c\u0435\u0440\u0443. \u0421\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u2014 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0437\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 Flush() \u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0441\u0440\u0430\u0437\u0443 \u0441\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0441\u043b\u043e\u0442 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e\u043c\u0435\u0442\u0438\u0432 batch \u043a\u0430\u043a \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0439. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0443\u0436\u043d\u043e \u0432 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 _lastReservationIndex, \u0438\u043d\u0430\u0447\u0435 \u043c\u044b \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0441\u043b\u043e\u0442\u043e\u0432 \u0437\u0430\u043d\u044f\u0442\u043e (\u0441\u043f\u043e\u0439\u043b\u0435\u0440: \u0442\u0443\u0442 \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 Interlocked.CompareExchange()). \u0412\u0441\u0435\u0433\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b 5 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439:<\/p>\n<ol>\n<li>_lastReservationIndex &lt; 0. flush-\u0438\u0442\u044c \u043d\u0435\u0447\u0435\u0433\u043e.<\/li>\n<li>_lastReservationIndex &gt;= _queue._batchSize. FlushInternal() \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442 \u043f\u043e\u0442\u043e\u043a, \u0441\u0445\u0432\u0430\u0442\u0438\u0432\u0448\u0438\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0441\u043b\u043e\u0442, \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043d\u0430\u0434\u043e.<\/li>\n<li>_lastReservationIndex \u0433\u043e\u0434\u043d\u044b\u0439 \u0438 \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0432 _queue._batchSize. \u041c\u044b \u0437\u043d\u0430\u0435\u043c \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b-\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435, \u043c\u043e\u0436\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c FlushInternal().<\/li>\n<li>\u041c\u0435\u0436\u0434\u0443 \u0447\u0442\u0435\u043d\u0438\u0435\u043c \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f _lastReservationIndex \u0438 \u0437\u0430\u043f\u0438\u0441\u044c\u044e \u0442\u0443\u0434\u0430 \u0436\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u043b\u0435\u0437 \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u0438 \u0441\u0445\u0432\u0430\u0442\u0438\u043b \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442. \u041f\u043e \u0441\u0443\u0442\u0438, \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u21162: \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u043c.<\/li>\n<li>\u0422\u043e \u0436\u0435 \u0447\u0442\u043e \u0432 \u21164, \u043d\u043e batch \u043d\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d. \u041a\u0440\u0443\u0442\u0438\u043c\u0441\u044f, \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0435\u0449\u0451 \u0440\u0430\u0437.<\/li>\n<\/ol>\n<p>  <\/p>\n<pre><code>\tpublic class AsyncBatchQueue&lt;T&gt;: IEnumerable&lt;IReadOnlyList&lt;T&gt;&gt; \t{ \t\t\/\/\t...  \t\tpublic void Flush() \t\t{ \t\t\tSpinWait spin = new SpinWait(); \t\t\twhile ( !_currentBatch.TryFlush() ) \t\t\t\tspin.SpinOnce(); \t\t}  \t\t\/\/\t...  \t\tprivate class Batch: IReadOnlyList&lt;T&gt; \t\t{ \t\t\t\/\/\t...\t\t\t  \t\t\tpublic bool TryFlush() \t\t\t{ \t\t\t\tint expectedPreviousReservation = Volatile.Read( ref _lastReservationIndex );  \t\t\t\t\/\/\tWe don't flush if the batch doesn't have any items or if another thread is about to flush it \t\t\t\t\/\/\tHowever, we report success to avoid unnecessary spinning. \t\t\t\tif ( expectedPreviousReservation &lt; 0 || expectedPreviousReservation &gt;= _queue._batchSize ) \t\t\t\t\treturn true;  \t\t\t\tint previousReservation = Interlocked.CompareExchange( ref _lastReservationIndex, _queue._batchSize, expectedPreviousReservation );  \t\t\t\t\/\/\tFlush reservation has succeeded. \t\t\t\tif ( expectedPreviousReservation == previousReservation ) \t\t\t\t{ \t\t\t\t\tFlushInternal( previousReservation + 1 ); \t\t\t\t\treturn true; \t\t\t\t}  \t\t\t\t\/\/\tThe following is true if someone has completed the batch by the time we tried to flush it. \t\t\t\t\/\/\tTherefore the batch will be flushed anyway even if we don't do anything. \t\t\t\t\/\/\tThe opposite means someone has slipped in an update and we have to spin. \t\t\t\treturn previousReservation &gt;= _queue._batchSize; \t\t\t}  \t\t\t\/\/\t... \t\t} \t} <\/code><\/pre>\n<p>  \u0413\u043e\u0442\u043e\u0432\u043e! \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0432\u0435\u0441\u0438\u0442\u044c \u0441\u0432\u0435\u0440\u0445\u0443 \u0442\u0430\u0439\u043c\u0435\u0440 \u2014 \u044d\u0442\u043e \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043b\u0438\u0448\u0451\u043d\u043d\u044b\u0439 \u043c\u0430\u0433\u0438\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441, \u0447\u0442\u043e \u044f \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u044e \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 \u043a\u043e\u043f\u0438\u043f\u0435\u0439\u0441\u0442\u0430 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0441 \u043d\u0438\u043c \u043a\u043e\u0434\u0430. \u0411\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u043e\u0432 \u0442\u043e\u0436\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442, \u0442.\u043a. \u044f \u043d\u0435 \u0437\u043d\u0430\u044e \u0441 \u043a\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/p>\n<h3>\u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435?<\/h3>\n<p>  \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043e\u0431\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0441\u0442\u0440\u0430\u0434\u0430\u044e\u0442 \u043e\u0442 \u043e\u0434\u043d\u043e\u0433\u043e \u0442\u043e\u043d\u043a\u043e\u0433\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0430. \u0415\u0441\u043b\u0438 \u043a\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u0441\u0434\u0435\u043b\u0430\u0435\u0442 Thread.Abort(), \u0442\u043e \u0432 \u0441\u0430\u043c\u044b\u0439 \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043b\u0435\u0442\u0435\u0442\u044c ThreadAbortException \u0438 \u0440\u0430\u0437\u0440\u0443\u0448\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u044c \u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0443\u044e \u043a\u043e\u043d\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439. \u0412 \u0432\u044b\u0448\u0435\u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u043e\u0439 ConcurrentQueue (\u0434\u0430 \u0438 \u0432 \u043a\u0443\u0447\u0435 \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u0435\u0441\u0442) \u044d\u0442\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u0432\u0435\u0441\u044c\u043c\u0430 \u044d\u043a\u0441\u0442\u0440\u0430\u0432\u0430\u0433\u0430\u043d\u0442\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>try { } finally { \t\/\/\tInsert Thread.Abort()-safe code here } <\/code><\/pre>\n<p>  \u041a\u0435\u0439\u0441 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0440\u0435\u0434\u043a\u0438\u0439, \u043d\u043e \u043d\u0430 \u0432\u0441\u044f\u043a\u0438\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u043e\u0442 \u043d\u0435\u0433\u043e \u0432\u0441\u0451 \u0436\u0435 \u0437\u0430\u0449\u0438\u0442\u0438\u0442\u044c\u0441\u044f. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043a\u043e\u0433\u0434\u0430-\u043d\u0438\u0431\u0443\u0434\u044c \u044f \u044d\u0442\u043e \u0432\u0441\u0451 \u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u044e.<\/p>\n<p>  \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0434\u043b\u044f \u0441\u0447\u0430\u0441\u0442\u044c\u044f \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0435\u0449\u0451 \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043e\u0434\u043d\u043e\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438: \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u0438. \u0418, \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 BlockingCollection, \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c TakeFromAny() \u043d\u0430 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0435 \u043d\u0435 \u0432\u0438\u0434\u043d\u043e. \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442?..<\/p>\n<h3>P.S.<\/h3>\n<p>  \u0414\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u0433\u0435\u0440\u043e\u0438\u0447\u0435\u0441\u043a\u0438 \u0434\u043e\u0447\u0438\u0442\u0430\u043b \u0434\u043e \u043a\u043e\u043d\u0446\u0430:<\/p>\n<p>  Nuget package: <a href=\"https:\/\/www.nuget.org\/packages\/AsyncCollections\/\">www.nuget.org\/packages\/AsyncCollections\/<\/a><br \/>  Source code: <a href=\"https:\/\/github.com\/HellBrick\/AsyncCollections\">github.com\/HellBrick\/AsyncCollections<\/a><\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043a\u0440\u0438\u0442\u0438\u043a\u0430, \u0431\u0430\u0433\u0438, \u043f\u043e\u0436\u0435\u043b\u0430\u043d\u0438\u044f \u0438\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0434\u0440\u0430\u0432\u044b\u0435 \u043c\u044b\u0441\u043b\u0438 \u2014 \u043f\u0438\u0448\u0438\u0442\u0435, \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c. \t\t\t<\/p>\n<div class=\"clear\"><\/div>\n<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/240891\/\"> http:\/\/habrahabr.ru\/post\/240891\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"content html_format\"> \t\t\t\u0421 \u0434\u0430\u0432\u043d\u0438\u0445 \u0432\u0440\u0435\u043c\u0451\u043d \u044f \u0431\u044b\u043b \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043f\u043e\u043a\u043b\u043e\u043d\u043d\u0438\u043a\u043e\u043c System.Collections.Concurrent \u0438 BlockingCollection \u0432 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438. \u0421\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u044d\u0442\u043e \u0447\u0443\u0434\u043e \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u043e\u0439 \u043c\u044b\u0441\u043b\u0438 \u0432\u044b\u0440\u0443\u0447\u0430\u043b\u043e \u0432 \u0441\u0430\u043c\u044b\u0445 \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u0435\u0439\u0448\u0438\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445 \u2014 \u043d\u0435 \u0441\u0447\u0435\u0441\u0442\u044c.<\/p>\n<p>  \u0421 \u0447\u0443\u0442\u044c \u043c\u0435\u043d\u0435\u0435 \u0434\u0440\u0435\u0432\u043d\u0438\u0445 \u0432\u0440\u0435\u043c\u0451\u043d \u0432 \u043e\u0431\u0438\u0445\u043e\u0434 \u043f\u0440\u043e\u0447\u043d\u043e \u0432\u043e\u0448\u043b\u0438 async\/await. \u041a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b, \u0436\u0438\u0437\u043d\u044c \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u0430, \u043d\u043e \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u043e \u00ab\u043d\u043e\u00bb: \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043c\u0438\u043a\u0441\u043e\u0432\u0430\u0442\u044c \u0441 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u043c \u043a\u043e\u0434\u043e\u043c \u043a\u0430\u043a-\u0442\u043e \u043d\u0435 \u043e\u0447\u0435\u043d\u044c-\u0442\u043e \u0445\u043e\u0447\u0435\u0442\u0441\u044f. \u0410 BlockingCollection, \u043a\u0430\u043a \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u0434\u043e\u0433\u0430\u0434\u0430\u0442\u044c\u0441\u044f (\u0445\u043e\u0442\u044f \u0431\u044b \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f), \u0432 \u0440\u044f\u0434\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u043f\u043e\u0442\u043e\u043a \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442.  <\/p>\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-240891","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/240891","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=240891"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/240891\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=240891"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=240891"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=240891"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}