Maximize TestServicesAsync performance
MODIFY
WalletWasabi.Tests/IntegrationTests/P2pTests.cs
WalletWasabi.Tests/IntegrationTests/P2pTests.cs
@@ -104,35 +104,27 @@ namespace WalletWasabi.Tests.IntegrationTests
try
{
- var mempoolTransactionAwaiter = new EventAwaiter<SmartTransaction>(
+ var mempoolTransactionAwaiter = new EventsAwaiter<SmartTransaction>(
h => bitcoinStore.MempoolService.TransactionReceived += h,
- h => bitcoinStore.MempoolService.TransactionReceived -= h);
+ h => bitcoinStore.MempoolService.TransactionReceived -= h,
+ 3);
- var nodeConnectionAwaiter = new EventAwaiter<NodeEventArgs>(
+ var nodeConnectionAwaiter = new EventsAwaiter<NodeEventArgs>(
h => nodes.ConnectedNodes.Added += h,
- h => nodes.ConnectedNodes.Added -= h);
+ h => nodes.ConnectedNodes.Added -= h,
+ 3);
nodes.Connect();
- await nodeConnectionAwaiter.Task.WithAwaitCancellationAsync(TimeSpan.FromMinutes(1));
-
- nodeConnectionAwaiter = new EventAwaiter<NodeEventArgs>(
- h => nodes.ConnectedNodes.Added += h,
- h => nodes.ConnectedNodes.Added -= h);
- await nodeConnectionAwaiter.Task.WithAwaitCancellationAsync(TimeSpan.FromMinutes(1));
-
- nodeConnectionAwaiter = new EventAwaiter<NodeEventArgs>(
- h => nodes.ConnectedNodes.Added += h,
- h => nodes.ConnectedNodes.Added -= h);
- await nodeConnectionAwaiter.Task.WithAwaitCancellationAsync(TimeSpan.FromMinutes(1));
-
var downloadTasks = new List<Task<Block>>();
+ using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(4));
foreach (var hash in blocksToDownload)
{
- using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3));
downloadTasks.Add(walletService.FetchBlockAsync(hash, cts.Token));
}
+ await Task.WhenAll(nodeConnectionAwaiter.Tasks).WithAwaitCancellationAsync(TimeSpan.FromMinutes(3));
+
var i = 0;
var hashArray = blocksToDownload.ToArray();
foreach (var block in await Task.WhenAll(downloadTasks))
@@ -141,7 +133,7 @@ namespace WalletWasabi.Tests.IntegrationTests
i++;
}
- await mempoolTransactionAwaiter.Task.WithAwaitCancellationAsync(TimeSpan.FromMinutes(1));
+ await Task.WhenAll(mempoolTransactionAwaiter.Tasks).WithAwaitCancellationAsync(TimeSpan.FromMinutes(1));
}
finally
{

MODIFY
WalletWasabi/Helpers/EventAwaiter.cs
WalletWasabi/Helpers/EventAwaiter.cs
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -8,25 +9,12 @@ namespace System
/// <summary>
/// https://stackoverflow.com/a/42117130/2061103
/// </summary>
- public class EventAwaiter<TEventArgs>
+ public class EventAwaiter<TEventArgs> : EventsAwaiter<TEventArgs>
{
- private TaskCompletionSource<TEventArgs> EventArrived { get; }
-
- private readonly Action<EventHandler<TEventArgs>> Unsubscribe;
-
- public EventAwaiter(Action<EventHandler<TEventArgs>> subscribe, Action<EventHandler<TEventArgs>> unsubscribe)
+ public EventAwaiter(Action<EventHandler<TEventArgs>> subscribe, Action<EventHandler<TEventArgs>> unsubscribe) : base(subscribe, unsubscribe, 1)
{
- EventArrived = new TaskCompletionSource<TEventArgs>();
- subscribe(Subscription);
- Unsubscribe = unsubscribe;
}
- public Task<TEventArgs> Task => EventArrived.Task;
-
- private EventHandler<TEventArgs> Subscription => (s, e) =>
- {
- EventArrived.TrySetResult(e);
- Unsubscribe(Subscription);
- };
+ public Task<TEventArgs> Task => EventsArrived.First().Task;
}
}

ADD
WalletWasabi/Helpers/EventsAwaiter.cs
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using WalletWasabi.Helpers;
+
+namespace System
+{
+ /// <summary>
+ /// https://stackoverflow.com/a/42117130/2061103
+ /// </summary>
+ public class EventsAwaiter<TEventArgs>
+ {
+ protected IEnumerable<TaskCompletionSource<TEventArgs>> EventsArrived { get; }
+
+ private Action<EventHandler<TEventArgs>> Unsubscribe { get; }
+ private object Lock { get; }
+
+ public EventsAwaiter(Action<EventHandler<TEventArgs>> subscribe, Action<EventHandler<TEventArgs>> unsubscribe, int count)
+ {
+ Guard.MinimumAndNotNull(nameof(count), count, 0);
+ Lock = new object();
+ var eventsArrived = new List<TaskCompletionSource<TEventArgs>>(count);
+ for (int i = 0; i < count; i++)
+ {
+ eventsArrived.Add(new TaskCompletionSource<TEventArgs>());
+ }
+ EventsArrived = eventsArrived;
+ subscribe(Subscription);
+ Unsubscribe = unsubscribe;
+ }
+
+ public IEnumerable<Task<TEventArgs>> Tasks => EventsArrived.Select(x => x.Task);
+
+ private EventHandler<TEventArgs> Subscription => (s, e) =>
+ {
+ lock (Lock)
+ {
+ var firstUnfinished = EventsArrived.FirstOrDefault(x => !x.Task.IsCompleted);
+ firstUnfinished?.TrySetResult(e);
+
+ if (EventsArrived.All(x => x.Task.IsCompleted))
+ {
+ Unsubscribe(Subscription);
+ }
+ }
+ };
+ }
+}

Maximize TestServicesAsync performance