Created
May 14, 2024 05:34
-
-
Save admir-live/0d6cb706acdea72b9cc0e9303cb4a9ae to your computer and use it in GitHub Desktop.
This C# file benchmarks various LINQ and PLINQ methods for analyzing potentially fraudulent transactions in different dataset sizes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Security.Cryptography; | |
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Reports; | |
using BenchmarkDotNet.Running; | |
public class Transaction | |
{ | |
public decimal Amount { get; } | |
public TimeSpan TransactionTime { get; } | |
public Transaction(decimal amount, TimeSpan transactionTime) | |
{ | |
Amount = amount; | |
TransactionTime = transactionTime; | |
} | |
} | |
public class TransactionFactory | |
{ | |
private const int MaxTransactionAmount = 20000; | |
private const int MinutesInADay = 1440; | |
private readonly RandomNumberGenerator _randomNumberGenerator = RandomNumberGenerator.Create(); | |
public List<Transaction> CreateTransactions(int count) | |
{ | |
List<Transaction> transactions = new List<Transaction>(); | |
for (int i = 0; i < count; i++) | |
{ | |
decimal amount = GenerateRandomAmount(); | |
double minutes = GenerateRandomMinutes(); | |
transactions.Add(new Transaction(amount, TimeSpan.FromMinutes(minutes))); | |
} | |
return transactions; | |
} | |
private decimal GenerateRandomAmount() | |
{ | |
return (decimal)(NextDouble(_randomNumberGenerator) * MaxTransactionAmount); | |
} | |
private double GenerateRandomMinutes() | |
{ | |
return NextDouble(_randomNumberGenerator) * MinutesInADay; | |
} | |
private static double NextDouble(RandomNumberGenerator rng) | |
{ | |
byte[] buffer = new byte[8]; | |
rng.GetBytes(buffer); | |
ulong ulongValue = BitConverter.ToUInt64(buffer, 0) / (1UL << 11); | |
return (double)ulongValue / (1UL << 53); | |
} | |
} | |
public class TransactionAnalysisBenchmark | |
{ | |
private const int SmallNumberOfTransactions = 1000; | |
private const int LargeNumberOfTransactions = 1000000; | |
private const decimal FraudulentAmountThreshold = 10000; | |
private List<Transaction> smallTransactionList; | |
private List<Transaction> largeTransactionList; | |
[GlobalSetup] | |
public void PrepareTransactionData() | |
{ | |
TransactionFactory transactionFactory = new TransactionFactory(); | |
smallTransactionList = transactionFactory.CreateTransactions(SmallNumberOfTransactions); | |
largeTransactionList = transactionFactory.CreateTransactions(LargeNumberOfTransactions); | |
} | |
[Benchmark] | |
public List<Transaction> PerformLinqQueryOnSmallTransactions() | |
{ | |
return smallTransactionList | |
.Where(IsTransactionPotentiallyFraudulent) | |
.ToList(); | |
} | |
[Benchmark] | |
public List<Transaction> PerformLinqQueryOnLargeTransactions() | |
{ | |
return largeTransactionList | |
.Where(IsTransactionPotentiallyFraudulent) | |
.ToList(); | |
} | |
[Benchmark] | |
public List<Transaction> PerformPLinqQueryOnSmallTransactionsSingleCore() | |
{ | |
return smallTransactionList.AsParallel() | |
.WithDegreeOfParallelism(1) | |
.Where(IsTransactionPotentiallyFraudulent) | |
.ToList(); | |
} | |
[Benchmark] | |
public List<Transaction> PerformPLinqQueryOnSmallTransactionsMaxCore() | |
{ | |
return smallTransactionList.AsParallel() | |
.WithDegreeOfParallelism(Environment.ProcessorCount) | |
.Where(IsTransactionPotentiallyFraudulent) | |
.ToList(); | |
} | |
[Benchmark] | |
public List<Transaction> PerformPLinqQueryOnLargeTransactionsSingleCore() | |
{ | |
return largeTransactionList.AsParallel() | |
.WithDegreeOfParallelism(1) | |
.Where(IsTransactionPotentiallyFraudulent) | |
.ToList(); | |
} | |
[Benchmark] | |
public List<Transaction> PerformPLinqQueryOnLargeTransactionsMaxCore() | |
{ | |
return largeTransactionList.AsParallel() | |
.WithDegreeOfParallelism(Environment.ProcessorCount) | |
.Where(IsTransactionPotentiallyFraudulent) | |
.ToList(); | |
} | |
public static bool IsTransactionPotentiallyFraudulent(Transaction transaction) | |
{ | |
return transaction is { Amount: > FraudulentAmountThreshold, TransactionTime.Hours: < 4 or 0x0 }; | |
} | |
public static void Main(string[] args) | |
{ | |
Summary summary = BenchmarkRunner.Run<TransactionAnalysisBenchmark>(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3447/23H2/2023Update/SunValley3)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK 8.0.204
[Host] : .NET 8.0.4 (8.0.424.16909), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.4 (8.0.424.16909), X64 RyuJIT AVX2