Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Мажирин Александр Homework 2 #44

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion homework 1/ReaderWriterLock/ReaderWriterLock.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="8.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
Expand Down
34 changes: 22 additions & 12 deletions homework 1/ReaderWriterLock/SharedReourceTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using System;
using System.Linq;
using System.Threading;
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Legacy;

namespace ReaderWriterLock;

[TestFixture]
public class SharedResourceTests
{
Expand All @@ -16,20 +14,32 @@ public class SharedResourceTests
[Test]
public void TestConcurrentReadWrite()
{
// Реализовать проверку конкурентной записи и чтения, где в конце должны проверить что данные последнего потока записаны
// Проверка должна быть многопоточной.
// Потоков чтения должно быть ReadersThreads, потоков записи должно быть WritersThreads

ClassicAssert.AreEqual($"Data {WritersThreads-1}", _sharedResource.Read());
_sharedResource = new SharedResourceLock();
TestSharedResource();
}

[Test]
public void TestConcurrentReadWriteRwLock()
{
// Реализовать проверку конкурентной записи и чтения, где в конце должны проверить что данные последнего потока записаны
// Проверка должна быть многопоточной
// Потоков чтения должно быть ReadersThreads, потоков записи должно быть WritersThreads
_sharedResource = new SharedResourceRwLock();
TestSharedResource();
}

private void TestSharedResource()
{
var threads = Enumerable
.Range(0, WritersThreads)
.Select(x => new Thread(() => _sharedResource.Write(x.ToString())))
.Concat(
Enumerable
.Range(0, ReadersThreads)
.Select(_ => new Thread(() => _sharedResource.Read())))
.ToArray();

ClassicAssert.AreEqual($"Data {WritersThreads-1}", _sharedResource.Read());
threads.ForEach(t => t.Start());
threads.ForEach(t => t.Join());

var expected = (WritersThreads - 1).ToString();
_sharedResource.Read()[^expected.Length..].Should().BeEquivalentTo(expected);
}
}
1 change: 1 addition & 0 deletions homework 1/ReaderWriterLock/SharedResourceBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public abstract class SharedResourceBase
public abstract void Write(string data);
public abstract string Read();
public abstract long ComputeFactorial(int number);
protected string SharedResource = string.Empty;

protected long Factorial(int number)
{
Expand Down
19 changes: 16 additions & 3 deletions homework 1/ReaderWriterLock/SharedResourceLock.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
using System.Threading;

namespace ReaderWriterLock;

public class SharedResourceLock : SharedResourceBase
{
private readonly Lock _lock = new();

public override void Write(string data)
{
throw new System.NotImplementedException();
lock (_lock)
{
SharedResource = data;
}
}

public override string Read()
{
throw new System.NotImplementedException();
lock (_lock)
{
return SharedResource;
}
}

public override long ComputeFactorial(int number)
{
throw new System.NotImplementedException();
lock (_lock)
{
return Factorial(number);
}
}
}
54 changes: 39 additions & 15 deletions homework 1/ReaderWriterLock/SharedResourcePerfomanceTests.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Legacy;

namespace ReaderWriterLock;

Expand All @@ -13,31 +13,55 @@ public class SharedResourcePerformanceTests
private SharedResourceBase _sharedResource;
private const int WritersThreads = 100;
private const int ReadersThreads = 1000;
private const int NumberOfIterations = 10000;
private const int FactorialNumber = 60; // Большое число для вычисления факториала
private const int NumberOfIterations = 1000;
private const int FactorialNumber = 60;

[Test]
public void TestLockPerformance()
{
_sharedResource = new SharedResourceLock();
long lockTime = MeasurePerformance();
var lockTime = MeasurePerformance();
Console.WriteLine($"Lock time taken: {lockTime} ms");

_sharedResource = new SharedResourceRwLock();
long rwLockTime = MeasurePerformance();
var rwLockTime = MeasurePerformance();
Console.WriteLine($"ReaderWriterLock time taken: {rwLockTime} ms");

// Проверка, что время выполнения с ReaderWriterLock меньше, чем с Lock
ClassicAssert.Less(rwLockTime, lockTime, "ReaderWriterLock should be faster than Lock");
rwLockTime.Should().BeLessThan(lockTime, "ReaderWriterLock should be faster than Lock");
}

private long MeasurePerformance()
{
// Нужно реализовать тест производительности.
// В многопоточном режиме нужно запустить:
// - Чтение общего ресурса в количестве ReadersThreads читающих потоков
// - Запись значений в количестве WritersThreads записывающих потоков
// - В вызовах читателей и писателей обязательно нужно вызывать подсчет факториала для симуляции полезной нагрузки
throw new NotImplementedException();
var threads = Enumerable
.Range(0, ReadersThreads)
.Select(_ => new Thread(Read))
.Concat(Enumerable.Range(0, WritersThreads).Select(_ => new Thread(Write)))
.ToArray();

var sw = Stopwatch.StartNew();
threads.ForEach(t => t.Start());
threads.ForEach(t => t.Join());
sw.Stop();

return sw.ElapsedMilliseconds;
}


private void Write()
{
for (var i = 0; i < NumberOfIterations; i++)
{
_sharedResource.Write(i.ToString());
_sharedResource.ComputeFactorial(FactorialNumber);
}
}

private void Read()
{
for (var i = 0; i < NumberOfIterations; i++)
{
_sharedResource.Read();
_sharedResource.ComputeFactorial(FactorialNumber);
}
}
}
33 changes: 30 additions & 3 deletions homework 1/ReaderWriterLock/SharedResourceRwLock.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,46 @@
using System.Threading;

namespace ReaderWriterLock;

public class SharedResourceRwLock : SharedResourceBase
{
private readonly ReaderWriterLockSlim _readerWriterLock = new();
public override void Write(string data)
{
throw new System.NotImplementedException();
_readerWriterLock.EnterWriteLock();
try
{
SharedResource = data;
}
finally
{
_readerWriterLock.ExitWriteLock();
}
}

public override string Read()
{
throw new System.NotImplementedException();
_readerWriterLock.EnterReadLock();
try
{
return SharedResource;
}
finally
{
_readerWriterLock.ExitReadLock();
}
}

public override long ComputeFactorial(int number)
{
throw new System.NotImplementedException();
_readerWriterLock.EnterReadLock();
try
{
return Factorial(number);
}
finally
{
_readerWriterLock.ExitReadLock();
}
}
}
13 changes: 13 additions & 0 deletions homework 2/ClusterClient/Clients/ClusterClientBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,18 @@ protected async Task<string> ProcessRequestAsync(WebRequest request)
return result;
}
}

protected async Task<string> TryProcessRequestAsync(WebRequest request)
{
try
{
return await ProcessRequestAsync(request);
}
catch (WebException ex)
{
Log.ErrorFormat("Request to {0} failed: {1}", request.RequestUri, ex.Message);
}
return null;
}
}
}
44 changes: 33 additions & 11 deletions homework 2/ClusterClient/Clients/ParallelClusterClient.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;

namespace ClusterClient.Clients
namespace ClusterClient.Clients;

public class ParallelClusterClient : ClusterClientBase
{
public class ParallelClusterClient : ClusterClientBase
protected override ILog Log => LogManager.GetLogger(typeof(ParallelClusterClient));

public ParallelClusterClient(string[] replicaAddresses) : base(replicaAddresses)
{
public ParallelClusterClient(string[] replicaAddresses) : base(replicaAddresses)
{
}
}

public override Task<string> ProcessRequestAsync(string query, TimeSpan timeout)
public override async Task<string> ProcessRequestAsync(string query, TimeSpan timeout)
{
var tasks = ReplicaAddresses
.Select(baseUri => CreateRequest(baseUri + "?query=" + query))
.Select(TryProcessRequestAsync)
.ToList();
var delay = Task.Delay(timeout);

while (tasks.Count != 0)
{
throw new NotImplementedException();
var task = Task.WhenAny(tasks);

await Task.WhenAny(task, delay);

if (delay.IsCompleted)
{
throw new TimeoutException();
}

if (task.Result.Result != null)
{
return task.Result.Result;
}

tasks.Remove(task.Result);
}

protected override ILog Log => LogManager.GetLogger(typeof(ParallelClusterClient));
return null;
}
}
}
8 changes: 4 additions & 4 deletions homework 2/ClusterClient/Clients/RandomClusterClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ClusterClient.Clients
{
public class RandomClusterClient : ClusterClientBase
{
private readonly Random random = new Random();
private readonly Random _random = new();

public RandomClusterClient(string[] replicaAddresses)
: base(replicaAddresses)
Expand All @@ -15,10 +15,10 @@ public RandomClusterClient(string[] replicaAddresses)

public override async Task<string> ProcessRequestAsync(string query, TimeSpan timeout)
{
var uri = ReplicaAddresses[random.Next(ReplicaAddresses.Length)];
var baseUri = ReplicaAddresses[_random.Next(ReplicaAddresses.Length)];

var webRequest = CreateRequest(baseUri + "?query=" + query);

var webRequest = CreateRequest(uri + "?query=" + query);

Log.InfoFormat($"Processing {webRequest.RequestUri}");

var resultTask = ProcessRequestAsync(webRequest);
Expand Down
Loading