From d63ea333f0c9952348b206bd717538ba82c58534 Mon Sep 17 00:00:00 2001 From: miyaji255 <84168445+miyaji255@users.noreply.github.com> Date: Sat, 16 Mar 2024 13:14:32 +0900 Subject: [PATCH] =?UTF-8?q?#19=20lock=E6=96=87=E3=81=AE=E7=AE=87=E6=89=80?= =?UTF-8?q?=E3=82=92=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/ScrapingClientService.cs | 137 ++++++++++-------- 1 file changed, 76 insertions(+), 61 deletions(-) diff --git a/Epub/KoeBook.Epub/Services/ScrapingClientService.cs b/Epub/KoeBook.Epub/Services/ScrapingClientService.cs index 1367980..4a6ac00 100644 --- a/Epub/KoeBook.Epub/Services/ScrapingClientService.cs +++ b/Epub/KoeBook.Epub/Services/ScrapingClientService.cs @@ -7,7 +7,7 @@ public sealed class ScrapingClientService : IScrapingClientService, IDisposable { private readonly IHttpClientFactory _httpClientFactory; private readonly PeriodicTimer _periodicTimer; - private readonly Queue> _actionQueue = []; + private readonly Queue> _actionQueue = []; private bool _workerActivated; public ScrapingClientService(IHttpClientFactory httpClientFactory, TimeProvider timeProvider) @@ -18,86 +18,101 @@ public ScrapingClientService(IHttpClientFactory httpClientFactory, TimeProvider Worker(); } - public void Dispose() + public Task GetAsStringAsync(string url, CancellationToken ct) { - _periodicTimer.Dispose(); - } + var taskCompletion = new TaskCompletionSource(); - private async void Worker() - { lock (_actionQueue) - { - _workerActivated = true; - } - - while (await _periodicTimer.WaitForNextTickAsync().ConfigureAwait(false) && _actionQueue.Count > 0) - { - if (_actionQueue.TryDequeue(out var action)) + _actionQueue.Enqueue(async httpClient => { - await action(_httpClientFactory.CreateClient()).ConfigureAwait(false); - } - } + if (ct.IsCancellationRequested) + taskCompletion.SetCanceled(ct); + + try + { + var response = await httpClient.GetAsync(url, ct).ConfigureAwait(false); + taskCompletion.SetResult(await response.Content.ReadAsStringAsync(ct).ConfigureAwait(false)); + } + catch (Exception ex) + { + taskCompletion.SetException(ex); + } + }); + + EnsureWorkerActivated(); - lock (_actionQueue) - { - _workerActivated = false; - } + return taskCompletion.Task; } - public Task GetAsStringAsync(string url, CancellationToken ct) + public Task GetAsStreamAsync(string url, Stream destination, CancellationToken ct) { - var taskCompletion = new TaskCompletionSource(); - _actionQueue.Enqueue(async httpClient => - { - if (ct.IsCancellationRequested) - taskCompletion.SetCanceled(ct); - - try - { - var response = await httpClient.GetAsync(url, ct).ConfigureAwait(false); - taskCompletion.SetResult(await response.Content.ReadAsStringAsync(ct).ConfigureAwait(false)); - } - catch (Exception ex) - { - taskCompletion.SetException(ex); - } - }); + var taskCompletion = new TaskCompletionSource(); lock (_actionQueue) - { - if (!_workerActivated) - Worker(); - } + _actionQueue.Enqueue(async httpClient => + { + if (ct.IsCancellationRequested) + taskCompletion.SetCanceled(ct); + + try + { + var response = await httpClient.GetAsync(url, ct).ConfigureAwait(false); + await response.Content.CopyToAsync(destination, ct).ConfigureAwait(false); + taskCompletion.SetResult(response.Content.Headers.ContentDisposition); + } + catch (Exception ex) + { + taskCompletion.SetException(ex); + } + }); + + EnsureWorkerActivated(); return taskCompletion.Task; } - public Task GetAsStreamAsync(string url, Stream destination, CancellationToken ct) + /// + /// が起動していない場合は起動します + /// + private void EnsureWorkerActivated() { - var taskCompletion = new TaskCompletionSource(); - _actionQueue.Enqueue(async httpClient => - { - if (ct.IsCancellationRequested) - taskCompletion.SetCanceled(ct); + bool activateWorker; + lock (_actionQueue) activateWorker = !_workerActivated; - try - { - var response = await httpClient.GetAsync(url, ct).ConfigureAwait(false); - await response.Content.CopyToAsync(destination, ct).ConfigureAwait(false); - taskCompletion.SetResult(response.Content.Headers.ContentDisposition); - } - catch (Exception ex) - { - taskCompletion.SetException(ex); - } - }); + if (activateWorker) + Worker(); + } + /// + /// のConsumer + /// 別スレッドでループさせるためにvoid + /// + private async void Worker() + { lock (_actionQueue) + _workerActivated = true; + + try { - if (!_workerActivated) - Worker(); + while (await _periodicTimer.WaitForNextTickAsync().ConfigureAwait(false) && _actionQueue.Count > 0) + { + Func? action; + lock (_actionQueue) + if (!_actionQueue.TryDequeue(out action)) + continue; + + await action(_httpClientFactory.CreateClient()).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing); + } } + finally + { + lock (_actionQueue) + _workerActivated = false; + } + } - return taskCompletion.Task; + public void Dispose() + { + _periodicTimer.Dispose(); } }