Free cookie consent management tool by TermsFeed Policy Generator

source: addons/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Data/Pool/ObjectPool.cs @ 17282

Last change on this file since 17282 was 15189, checked in by pkimmesw, 7 years ago

#2665 Fixed small issues, testet benchmark suite, added INX Expressions

File size: 4.2 KB
Line 
1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5using System;
6
7namespace HeuristicLab.Problems.ProgramSynthesis.Push.Data.Pool {
8  using System.Collections.Generic;
9  using System.Threading;
10
11  /// <summary>
12  /// Generic implementation of object pooling pattern with predefined pool size limit. The main
13  /// purpose is that limited number of frequently used objects can be kept in the pool for
14  /// further recycling.
15  ///
16  /// Notes:
17  /// 1) it is not the goal to keep all returned objects. Pool is not meant for storage. If there
18  ///    is no space in the pool, extra returned objects will be dropped.
19  ///
20  /// 2) it is implied that if object was obtained from a pool, the caller will return it back in
21  ///    a relatively short time. Keeping checked out objects for long durations is ok, but
22  ///    reduces usefulness of pooling. Just new up your own.
23  ///
24  /// Not returning objects to the pool in not detrimental to the pool's work, but is a bad practice.
25  /// Rationale:
26  ///    If there is no intent for reusing the object, do not use pool - just use "new".
27  /// </summary>
28  public sealed class ObjectPool<T> where T : class {
29    private struct Element {
30      internal T Value;
31    }
32
33    // storage for the pool objects.
34    private readonly Element[] _items;
35
36    // factory is stored for the lifetime of the pool. We will call this only when pool needs to
37    // expand. compared to "new T()", Func gives more flexibility to implementers and faster
38    // than "new T()".
39    private readonly Func<T> _factory;
40
41
42    public ObjectPool(Func<T> factory)
43        : this(factory, Environment.ProcessorCount * 2) { }
44
45    public ObjectPool(Func<T> factory, int size) {
46      _factory = factory;
47      _items = new Element[size];
48    }
49
50    private T CreateInstance() {
51      var inst = _factory();
52      return inst;
53    }
54
55    /// <summary>
56    /// Produces an instance.
57    /// </summary>
58    /// <remarks>
59    /// Search strategy is a simple linear probing which is chosen for it cache-friendliness.
60    /// Note that Free will try to store recycled objects close to the start thus statistically
61    /// reducing how far we will typically search.
62    /// </remarks>
63    public T Allocate() {
64      var items = _items;
65      T inst;
66
67      for (int i = 0; i < items.Length; i++) {
68        // Note that the read is optimistically not synchronized. That is intentional.
69        // We will interlock only when we have a candidate. in a worst case we may miss some
70        // recently returned objects. Not a big deal.
71        inst = items[i].Value;
72        if (inst != null) {
73          if (inst == Interlocked.CompareExchange(ref items[i].Value, null, inst)) {
74            goto gotInstance;
75          }
76        }
77      }
78
79      inst = CreateInstance();
80      gotInstance:
81
82      return inst;
83    }
84
85    /// <summary>
86    /// Returns objects to the pool.
87    /// </summary>
88    /// <remarks>
89    /// Search strategy is a simple linear probing which is chosen for it cache-friendliness.
90    /// Note that Free will try to store recycled objects close to the start thus statistically
91    /// reducing how far we will typically search in Allocate.
92    /// </remarks>
93    public void Free(T obj) {
94      var items = _items;
95      for (int i = 0; i < items.Length; i++) {
96        if (items[i].Value == null) {
97          // Intentionally not using interlocked here.
98          // In a worst case scenario two objects may be stored into same slot.
99          // It is very unlikely to happen and will only mean that one of the objects will get collected.
100          items[i].Value = obj;
101          break;
102        }
103      }
104    }
105
106    public void Clear() {
107      for (int i = 0; i < _items.Length; i++) {
108        _items[i] = default(Element);
109      }
110    }
111
112    public IEnumerable<T> Items
113    {
114      get
115      {
116        var items = _items;
117        for (var i = 0; i < items.Length; i++) {
118          if (items[i].Value != null) {
119            yield return items[i].Value;
120          }
121        }
122      }
123    }
124  }
125}
Note: See TracBrowser for help on using the repository browser.