Skip to content
This repository has been archived by the owner on May 21, 2022. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/origin/dev-pomma89'
Browse files Browse the repository at this point in the history
  • Loading branch information
pomma89 committed Apr 8, 2017
2 parents c54a20e + 4521572 commit 3372e80
Show file tree
Hide file tree
Showing 20 changed files with 532 additions and 316 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog for CodeProject.ObjectPool #

### v3.0.3 (2017-04-08) ###

* Added a timed object pool (issue #1).
* OnReleaseResources and OnResetState are now simple actions on PooledObject.

### v3.0.2 (2017-04-02) ###

* Moved core pool buffer into dedicated class: Core.PooledObjectBuffer.
Expand Down
7 changes: 7 additions & 0 deletions NuGet.Config
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!-- Add this repository to the list of available repositories -->
<add key="myget/pomma89" value="https://www.myget.org/F/pomma89/api/v3/index.json" />
</packageSources>
</configuration>
3 changes: 2 additions & 1 deletion ObjectPool.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.9
VisualStudioVersion = 15.0.26403.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "root", "root", "{4C2B7C0C-7CDD-4125-B57A-88E168D24190}"
ProjectSection(SolutionItems) = preProject
Expand All @@ -11,6 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "root", "root", "{4C2B7C0C-7
build.cake = build.cake
CHANGELOG.md = CHANGELOG.md
LICENSE.htm = LICENSE.htm
NuGet.Config = NuGet.Config
pomma89.snk = pomma89.snk
README.md = README.md
EndProjectSection
Expand Down
151 changes: 84 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ A generic, concurrent, portable and flexible Object Pool for the .NET Framework,

## Summary ##

* Latest release version: `v3.0.2`
* Latest release version: `v3.0.3`
* Build status on [AppVeyor](https://ci.appveyor.com): [![Build status](https://ci.appveyor.com/api/projects/status/r4qnqaqj9ri6cicn?svg=true)](https://ci.appveyor.com/project/pomma89/objectpool)
* [Doxygen](http://www.stack.nl/~dimitri/doxygen/index.html) documentation:
+ [HTML](https://goo.gl/RVA7mV)
Expand Down Expand Up @@ -37,9 +37,9 @@ internal static class Program
/// </summary>
private static void Main()
{
// Creating a pool with minimum size of 5 and maximum size of 25, using custom Factory
// method to create and instance of ExpensiveResource.
var pool = new ObjectPool<ExpensiveResource>(5, 25, () => new ExpensiveResource(/* resource specific initialization */));
// Creating a pool with a maximum size of 25, using custom Factory method to create and
// instance of ExpensiveResource.
var pool = new ObjectPool<ExpensiveResource>(25, () => new ExpensiveResource(/* resource specific initialization */));

using (var resource = pool.GetObject())
{
Expand All @@ -52,15 +52,31 @@ internal static class Program
var newPool = new ObjectPool<PooledObjectWrapper<ExternalExpensiveResource>>(() =>
new PooledObjectWrapper<ExternalExpensiveResource>(CreateNewResource())
{
WrapperReleaseResourcesAction = r => ExternalResourceReleaseResource(r),
WrapperResetStateAction = r => ExternalResourceResetState(r)
OnReleaseResources = ExternalResourceReleaseResource,
OnResetState = ExternalResourceResetState
});

using (var wrapper = newPool.GetObject())
{
// wrapper.InternalResource contains the object that you pooled.
wrapper.InternalResource.DoOtherStuff();
} // Exiting the using scope will return the object back to the pool.
// Creates a pool where objects which have not been used for over 2 seconds will be
// cleaned up by a dedicated thread.
var timedPool = new TimedObjectPool<ExpensiveResource>(TimeSpan.FromSeconds(2));

using (var resource = timedPool.GetObject())
{
// Using the resource...
resource.DoStuff();
} // Exiting the using scope will return the object back to the pool and record last usage.
Console.WriteLine($"Timed pool size after 0 seconds: {timedPool.ObjectsInPoolCount}"); // Should be 1
Thread.Sleep(TimeSpan.FromSeconds(4));
Console.WriteLine($"Timed pool size after 4 seconds: {timedPool.ObjectsInPoolCount}"); // Should be 0
Console.Read();
}

private static ExternalExpensiveResource CreateNewResource()
Expand All @@ -81,19 +97,22 @@ internal static class Program

internal sealed class ExpensiveResource : PooledObject
{
public void DoStuff()
public ExpensiveResource()
{
// Do some work here, for example.
}
OnReleaseResources = () =>
{
// Called if the resource needs to be manually cleaned before the memory is reclaimed.
};

protected override void OnReleaseResources()
{
// Override if the resource needs to be manually cleaned before the memory is reclaimed.
OnResetState = () =>
{
// Called if the resource needs resetting before it is getting back into the pool.
};
}

protected override void OnResetState()
public void DoStuff()
{
// Override if the resource needs resetting before it is getting back into the pool.
// Do some work here, for example.
}
}

Expand All @@ -112,91 +131,89 @@ All benchmarks were implemented and run using the wonderful [BenchmarkDotNet](ht

### [Retrieve one object](https://github.com/pomma89/ObjectPool/blob/master/ObjectPool.Benchmarks/RetrieveOneObject.cs) ###

In this benchmark we evaluate how long it takes to extract and return an object stored into the pool, using a single thread. We compare three implementations:
In this benchmark we evaluate how long it takes to extract and return an object stored into the pool, using a single thread. We compare four implementations:

* [This project's ObjectPool](https://github.com/pomma89/ObjectPool/blob/master/ObjectPool/ObjectPool.cs)
* [This project's ParameterizedObjectPool](https://github.com/pomma89/ObjectPool/blob/master/ObjectPool/ParameterizedObjectPool.cs)
* [Microsoft's ObjectPool](http://www.nuget.org/packages/Microsoft.Extensions.ObjectPool/)
* [Original ObjectPool](http://www.codeproject.com/Articles/535735/Implementing-a-Generic-Object-Pool-in-NET)

```ini
``` ini

Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i3-2330M CPU 2.20GHz, ProcessorCount=4
Frequency=14318180 ticks, Resolution=69.8413 ns, Timer=HPET
CLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE
GC=Concurrent Workstation
JitModules=clrjit-v4.6.1586.0
BenchmarkDotNet=v0.10.3.0, OS=Microsoft Windows NT 6.2.9200.0
Processor=AMD A10 Extreme Edition Radeon R8, 4C+8G, ProcessorCount=4
Frequency=1949470 Hz, Resolution=512.9599 ns, Timer=TSC
[Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0
RyuJitX64 : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0

Type=RetrieveOneObject Mode=Throughput
Job=RyuJitX64 Jit=RyuJit Platform=X64

```
Method | Median | StdDev | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op |
------------------------ |------------ |---------- |------ |------ |------ |------------------- |
SimpleObjectPool | 136.0373 ns | 3.4367 ns | 11.02 | 9.58 | 9.58 | 3,09 |
ParameterizedObjectPool | 199.7968 ns | 4.4435 ns | 21.00 | - | - | 3,08 |
MicrosoftObjectPool | 60.7935 ns | 1.8593 ns | - | - | - | 0,00 |
| Method | Mean | StdDev | Gen 0 | Allocated |
|------------------------ |-------------- |----------- |------- |---------- |
| SimpleObjectPool | 106.3367 ns | 1.9033 ns | - | 0 B |
| ParameterizedObjectPool | 174.2507 ns | 1.9017 ns | 0.0391 | 24 B |
| MicrosoftObjectPool | 59.3673 ns | 1.2349 ns | - | 0 B |
| OriginalObjectPool | 1,773.9186 ns | 96.7615 ns | 0.0238 | 240 B |

### [Retrieve objects concurrently](https://github.com/pomma89/ObjectPool/blob/master/ObjectPool.Benchmarks/RetrieveObjectsConcurrently.cs) ###

In this benchmark we evaluate how long it takes to extract and return an object stored into the pool, using `Count` threads. We compare three implementations:
In this benchmark we evaluate how long it takes to extract and return an object stored into the pool, using `Count` threads. We compare four implementations:

* [This project's ObjectPool](https://github.com/pomma89/ObjectPool/blob/master/ObjectPool/ObjectPool.cs)
* [This project's ParameterizedObjectPool](https://github.com/pomma89/ObjectPool/blob/master/ObjectPool/ParameterizedObjectPool.cs)
* [Microsoft's ObjectPool](http://www.nuget.org/packages/Microsoft.Extensions.ObjectPool/)
* [Original ObjectPool](http://www.codeproject.com/Articles/535735/Implementing-a-Generic-Object-Pool-in-NET)

```ini
``` ini

Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i3-2330M CPU 2.20GHz, ProcessorCount=4
Frequency=14318180 ticks, Resolution=69.8413 ns, Timer=HPET
CLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE
GC=Concurrent Workstation
JitModules=clrjit-v4.6.1586.0
BenchmarkDotNet=v0.10.3.0, OS=Microsoft Windows NT 6.2.9200.0
Processor=AMD A10 Extreme Edition Radeon R8, 4C+8G, ProcessorCount=4
Frequency=1949470 Hz, Resolution=512.9599 ns, Timer=TSC
[Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0
RyuJitX64 : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0

Type=RetrieveObjectsConcurrently Mode=Throughput Affinity=2
Job=RyuJitX64 Jit=RyuJit Platform=X64

```
Method | Count | Median | StdDev | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op |
------------------------ |------ |------------ |---------- |------ |------ |------ |------------------- |
**SimpleObjectPool** | **10** | **5.7390 us** | **0.3109 us** | **1.72** | **0.72** | **0.07** | **278,68** |
ParameterizedObjectPool | 10 | 6.4189 us | 1.1792 us | 1.58 | 1.23 | - | 284,70 |
MicrosoftObjectPool | 10 | 4.2985 us | 0.0975 us | 1.30 | 1.11 | - | 244,84 |
**SimpleObjectPool** | **100** | **19.6048 us** | **1.2525 us** | **3.04** | **2.32** | **0.73** | **576,85** |
ParameterizedObjectPool | 100 | 27.8705 us | 1.9570 us | 3.09 | 2.81 | - | 560,35 |
MicrosoftObjectPool | 100 | 10.5264 us | 1.5110 us | 1.78 | 0.97 | 0.03 | 233,25 |
**SimpleObjectPool** | **1000** | **157.9986 us** | **6.2393 us** | **12.67** | **12.12** | **9.92** | **3.277,64** |
ParameterizedObjectPool | 1000 | 223.4054 us | 7.6698 us | 20.00 | - | - | 2.697,82 |
MicrosoftObjectPool | 1000 | 76.3736 us | 0.8204 us | 5.17 | 0.29 | - | 247,38 |
| Method | Count | Mean | StdDev | Gen 0 | Gen 1 | Allocated |
|------------------------ |------ |-------------- |----------- |-------- |-------- |---------- |
| **SimpleObjectPool** | **10** | **10.1346 us** | **0.3799 us** | **1.7548** | **-** | **1.12 kB** |
| ParameterizedObjectPool | 10 | 13.6740 us | 0.3560 us | 1.9409 | - | 1.42 kB |
| MicrosoftObjectPool | 10 | 9.3135 us | 0.1154 us | 1.7008 | - | 1.12 kB |
| OriginalObjectPool | 10 | 26.4688 us | 0.7511 us | - | - | 3.7 kB |
| **SimpleObjectPool** | **100** | **54.1560 us** | **1.7507 us** | **-** | **-** | **1.31 kB** |
| ParameterizedObjectPool | 100 | 72.3400 us | 0.8960 us | 4.8177 | - | 3.93 kB |
| MicrosoftObjectPool | 100 | 30.9284 us | 1.1752 us | 2.9975 | - | 2.16 kB |
| OriginalObjectPool | 100 | 177.0052 us | 3.7795 us | 1.7904 | - | 27.04 kB |
| **SimpleObjectPool** | **1000** | **689.5726 us** | **21.9610 us** | **-** | **-** | **4.07 kB** |
| ParameterizedObjectPool | 1000 | 844.7284 us | 19.1851 us | 10.9863 | - | 28.18 kB |
| MicrosoftObjectPool | 1000 | 362.2347 us | 21.3030 us | 51.1351 | 15.1438 | 28.3 kB |
| OriginalObjectPool | 1000 | 1,458.5456 us | 25.8381 us | 29.1667 | - | 268.99 kB |


### [Memory stream pooling](https://github.com/pomma89/ObjectPool/blob/master/ObjectPool.Benchmarks/MemoryStreamPooling.cs) ###

In this benchmark we evaluate how long it takes to extract and return a memory stream stored into the pool, using a single thread. We compare three implementations:
In this benchmark we evaluate how long it takes to extract and return a memory stream stored into the pool, using a single thread. We compare two implementations:

* [This project's MemoryStreamPool](https://github.com/pomma89/ObjectPool/blob/master/ObjectPool/Specialized/MemoryStreamPool.cs)
* [Microsoft's RecyclableMemoryStreamManager](http://www.nuget.org/packages/Microsoft.IO.RecyclableMemoryStream/)

```ini
``` ini

Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i3-2330M CPU 2.20GHz, ProcessorCount=4
Frequency=14318180 ticks, Resolution=69.8413 ns, Timer=HPET
CLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE
GC=Concurrent Workstation
JitModules=clrjit-v4.6.1586.0
BenchmarkDotNet=v0.10.3.0, OS=Microsoft Windows NT 6.2.9200.0
Processor=AMD A10 Extreme Edition Radeon R8, 4C+8G, ProcessorCount=4
Frequency=1949470 Hz, Resolution=512.9599 ns, Timer=TSC
[Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0
RyuJitX64 : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0

Type=MemoryStreamPooling Mode=Throughput
Job=RyuJitX64 Jit=RyuJit Platform=X64

```
Method | Median | StdDev | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op |
------------------------------ |-------------- |------------ |------- |------ |------ |------------------- |
MemoryStreamPool | 171.7594 ns | 4.7127 ns | 1.46 | 1.26 | 1.26 | 3,08 |
RecyclableMemoryStreamManager | 2,924.0579 ns | 117.2652 ns | 341.00 | - | - | 88,74 |
| Method | Mean | StdErr | StdDev | Gen 0 | Allocated |
|------------------------------ |-------------- |----------- |------------ |------- |---------- |
| MemoryStreamPool | 180.0207 ns | 1.6126 ns | 6.0337 ns | - | 0 B |
| RecyclableMemoryStreamManager | 4,213.5708 ns | 44.6009 ns | 446.0087 ns | 0.8134 | 448 B |

## About this repository and its maintainer ##

Expand Down
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#---------------------------------#

# version format
version: 3.0.2.{build}
version: 3.0.3.{build}

# branches to build
branches:
Expand All @@ -25,7 +25,7 @@ branches:
assembly_info:
patch: true
file: AssemblyInfo.*
assembly_version: "3.0.2.{build}"
assembly_version: "3.0.3.{build}"
assembly_file_version: "{version}"
assembly_informational_version: "{version}"

Expand Down
66 changes: 33 additions & 33 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ private void Build(string cfg)
// NoIncremental = true
// });
//}
MSBuild(solutionFile, settings =>
{
MSBuild(solutionFile, settings =>
{
settings.SetConfiguration(cfg);
settings.SetMaxCpuCount(0);
});
settings.SetMaxCpuCount(0);
});
}

private void Test(string cfg)
Expand All @@ -107,43 +107,43 @@ private void Test(string cfg)
// NoResults = true
//});

const string flags = "--noheader --noresult";
const string errMsg = " - Unit test failure - ";

Parallel.ForEach(GetFiles("./test/**/bin/{cfg}/*/*.UnitTests.exe".Replace("{cfg}", cfg)), netExe =>
{
if (StartProcess(netExe, flags) != 0)
{
throw new Exception(cfg + errMsg + netExe);
}
});

Parallel.ForEach(GetFiles("./test/**/bin/{cfg}/*/*.UnitTests.dll".Replace("{cfg}", cfg)), netCoreDll =>
{
DotNetCoreExecute(netCoreDll, flags);
});
const string flags = "--noheader --noresult";
const string errMsg = " - Unit test failure - ";

Parallel.ForEach(GetFiles("./test/**/bin/{cfg}/*/*.UnitTests.exe".Replace("{cfg}", cfg)), netExe =>
{
if (StartProcess(netExe, flags) != 0)
{
throw new Exception(cfg + errMsg + netExe);
}
});

Parallel.ForEach(GetFiles("./test/**/bin/{cfg}/*/*.UnitTests.dll".Replace("{cfg}", cfg)), netCoreDll =>
{
DotNetCoreExecute(netCoreDll, flags);
});
}

private void Pack(string cfg)
{
Parallel.ForEach(GetFiles("./src/**/*.csproj"), project =>
{
Parallel.ForEach(GetFiles("./src/**/*.csproj"), project =>
{
//DotNetCorePack(project.FullPath, new DotNetCorePackSettings
//{
// Configuration = cfg,
// OutputDirectory = artifactsDir,
// NoBuild = true
//});

MSBuild(project, settings =>
{
settings.SetConfiguration(cfg);
settings.SetMaxCpuCount(0);
settings.WithTarget("pack");
settings.WithProperty("IncludeSymbols", new[] { "true" });
});

var packDir = project.GetDirectory().Combine("bin").Combine(cfg);
MoveFiles(GetFiles(packDir + "/*.nupkg"), artifactsDir);
});
MSBuild(project, settings =>
{
settings.SetConfiguration(cfg);
settings.SetMaxCpuCount(0);
settings.WithTarget("pack");
settings.WithProperty("IncludeSymbols", new[] { "true" });
});

var packDir = project.GetDirectory().Combine("bin").Combine(cfg);
MoveFiles(GetFiles(packDir + "/*.nupkg"), artifactsDir);
});
}
6 changes: 1 addition & 5 deletions src/CodeProject.ObjectPool/CodeProject.ObjectPool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<AssemblyName>CodeProject.ObjectPool</AssemblyName>
<AssemblyTitle>Generic and concurrent Object Pool</AssemblyTitle>
<VersionPrefix>3.0.2</VersionPrefix>
<VersionPrefix>3.0.3</VersionPrefix>
<TargetFrameworks>netstandard1.0;netstandard1.1;netstandard1.2;netstandard1.3;net35;net40;net45</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyOriginatorKeyFile>../../pomma89.snk</AssemblyOriginatorKeyFile>
Expand Down Expand Up @@ -80,8 +80,4 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
</ItemGroup>

<ItemGroup>
<Folder Include="Extensibility\" />
</ItemGroup>
</Project>
Loading

0 comments on commit 3372e80

Please sign in to comment.