ऑब्जेक्ट पूल पैटर्न

From alpha
Jump to navigation Jump to search

ऑब्जेक्ट पूल पैटर्न (ओपीपी) एक सॉफ़्टवेयर आधुनिक डिज़ाइन रूपांतरण है जो प्रारंभिक वस्तुओं के एक समूह का उपयोग करता है तथा आवश्यकता के अनुसार मेमोरी आवंटित करने और नष्ट करने के अतिरिक्त "पूल" का उपयोग करने के लिए डिज़ाइन किया जाता है। पूल का प्रयोग उपयोगकर्ता-पूल से किसी ऑब्जेक्ट (वस्तु) का अनुरोध करता है और वापस किए गए ऑब्जेक्ट पर डेटा संचालन करता है जब उपयोगकर्ता समाप्त हो जाता है तो यह वस्तु को नष्ट करने के अतिरिक्त पूल में वापस डेटा संचालित करता है यह मैन्युअल या स्वचालित दोनों रूप से उपयोग किया जा सकता है।

ऑब्जेक्ट पूल मुख्य रूप से डेटा प्रदर्शन के लिए उपयोग किए जाते हैं कुछ स्थितियों में, ऑब्जेक्ट पूल प्रदर्शन में अपेक्षाकृत सुधार करते हैं। ऑब्जेक्ट पूल वस्तु के रनटाइम को जटिल बनाते हैं, क्योंकि पूल से प्राप्त और वापस किए गए ऑब्जेक्ट डेटा इस समय बनाए या नष्ट नहीं किए जाते हैं और इस प्रकार कार्यान्वयन में संरक्षण की आवश्यकता होती है।

विवरण

जब कई वस्तुओं के साथ कार्य करना आवश्यक होता है जो विशेष रूप से कीमती होती हैं और प्रत्येक वस्तु की आवश्यकता केवल अपेक्षाकृत समय के लिए होती है तो संपूर्ण अनुप्रयोग का प्रदर्शन प्रतिकूल रूप से प्रभावित हो सकता है। ऐसे स्थितियों में ऑब्जेक्ट पूल डिज़ाइन पैटर्न को वांछनीय माना जा सकता है।

ऑब्जेक्ट पूल डिज़ाइन पैटर्न उन वस्तुओं का एक समूह बनाता है जिनका पुन: उपयोग किया जा सकता है। जब किसी नई वस्तु की आवश्यकता होती है, तो उसे पूल से अनुरोध किया जाता है। यदि पहले से तैयार वस्तु उपलब्ध है तो वर्तमान लागत से बचते हुए, इसे शीघ्र वापस कर दिया जाता है। यदि पूल में कोई वस्तु सम्मिलित नहीं है, तो एक नयी वस्तु बनाई जाती है और वापस की जाता है। जब ऑब्जेक्ट का उपयोग किया गया है और अब इसकी आवश्यकता नहीं है तो इसे पूल में वापस कर दिया जाता है जिससे इसे भविष्य में कम्प्यूटेशनल रूप से कीमती वर्तमान प्रक्रिया को दोहराए बिना फिर से उपयोग करने की स्वीकृति प्राप्त होती है। यह ध्यान रखना महत्वपूर्ण होता है कि एक बार किसी वस्तु का उपयोग करने के बाद उसमे सम्मिलित संदर्भ अमान्य हो जाते है।

कुछ ऑब्जेक्ट पूल में संसाधन सीमित होते हैं, इसलिए ऑब्जेक्ट्स की अधिकतम संख्या निर्दिष्ट की जाती है। यदि यह संख्या पूर्ण हो जाती है तब एक नई वस्तु का अनुरोध किया जाता है जिसे विशिष्ट रूप से मुफ्त किया जा सकता है या थ्रेड को तब तक ब्लॉक किया जाएगा जब तक कि ऑब्जेक्ट पूल में वापस नहीं आ जाता है।

ऑब्जेक्ट पूल डिज़ाइन पैटर्न का उपयोग डॉटनेट फ्रेमवर्क के मानक वर्गों में कई स्थानों पर किया जाता है। एक उदाहरण एसक्यूएल सर्वर के लिए डॉटनेट फ्रेमवर्क डेटा प्रदाता है। चूंकि एसक्यूएल सर्वर डेटाबेस संयोजन बनाने में अपेक्षाकृत धीमा हो सकता है, डेटा संबंध का पूल बनाए रखा जाता है। डेटा संबंध को स्थगित करना वास्तव में एसक्यूएल सर्वर से लिंक को अलग करना नहीं होता है। इसके अतिरिक्त, डेटा संबंध को पूल में रखा जाता है जिससे नए डेटा संबंध का अनुरोध करते समय इसे पुनर्प्राप्त किया जा सकता है। यह डेटा संबंध बनाने की गति को अपेक्षाकृत रूप से अत्यधिक विस्तृत करता है।

लाभ

ऑब्जेक्ट पूलिंग उन स्थितियों में महत्वपूर्ण प्रदर्शन को प्रभावित कर सकते है जहां एक क्लास-अनुरोध को प्रारम्भ करने की लागत अधिक होती है और एक क्लास के प्रारम्भ और नष्ट होने की दर उच्च होती है इस स्थितिे में ऑब्जेक्ट्स का बार-बार पुन: उपयोग किया जा सकता है और प्रत्येक ऑब्जेक्ट के पुन: उपयोग से महत्वपूर्ण डेटा में बचत होती है। ऑब्जेक्ट पूलिंग के लिए संसाधनों की आवश्यकता होती है मेमोरी और संभवतः अन्य संसाधन जैसे कि नेटवर्क और इस प्रकार यह अपेक्षाकृत विस्तृत होता है कि किसी एक समय में उपयोग किए जाने वाले उदाहरणों की संख्या कम हो लेकिन इसकी आवश्यकता नहीं होती है।

पूल की गई वस्तु अनुमानित समय में प्राप्त होती है जब नई वस्तुओं (विशेष रूप से नेटवर्क पर) के निर्माण में परिवर्तनशील समय लग सकता है। ये लाभ अधिकाश उन वस्तुओं के लिए सही हैं जो समय के साथ कीमती हैं जैसे डेटाबेस संबंध, सॉकेट डेटा संबंध, थ्रेड्स और बड़े ग्राफिक ऑब्जेक्ट्स जैसे फोंट या बिटमैप्स और अन्य स्थितियों में, साधारण ऑब्जेक्ट पूलिंग (जिसमें कोई बाहरी संसाधन नहीं होता है, लेकिन केवल मेमोरी पर अधिकृत होता है) कुशल नहीं हो सकता है और प्रदर्शन को कम कर सकता है।[1] साधारण मेमोरी पूलिंग की स्थितिे में, स्लैब आवंटन मेमोरी प्रबंधन तकनीक अधिक अनुकूल है, क्योंकि एकमात्र मेमोरी विखंडन (फ्रैग्मेंटेशन) को कम करके मेमोरी आवंटन और डीलोकेशन की लागत को कम किया जा सकता है।

कार्यान्वयन

ऑब्जेक्ट पूल को पॉइंटर (प्रोग्रामिंग) के माध्यम से सी ++ जैसी भाषाओं में स्वचालित तरीके से कार्यान्वित किया जा सकता है। पॉइंटर के निर्माण में, ऑब्जेक्ट को पूल से अनुरोध किया जा सकता है और पॉइंटर को नष्ट करने के लिए, ऑब्जेक्ट को पूल में वापस भेजा जा सकता है। गार्बेज़ डेटा एकत्र करने वाली भाषाओं में, जहां कोई विध्वंसक नहीं है जो स्टैक-अनविंड के भाग के रूप में कहे जाने का दायित्व है ऑब्जेक्ट पूल को मैन्युअल रूप से प्रयुक्त किया जाना चाहिए, स्पष्ट रूप से फैक्टरी (वस्तु-उन्मुख प्रोग्रामिंग) से किसी भी वस्तु का अनुरोध करके और डिस्पोस विधि को कॉल करके वस्तु को वापस करना सम्मिलित होता है डिस्पोज पैटर्न के अनुसार ऐसा करने के लिए फ़ाइनलाइज़र का उपयोग करना एक अपेक्षाकृत रूप से अच्छा नहीं है क्योंकि फ़ाइनलाइज़र कब सक्रिय किया जा सकता है इसका कोई निर्धारित समय नहीं होता है।

इसके अतिरिक्त इसका उपयोग यह सुनिश्चित करने के लिए किया जाना चाहिए कि वस्तु प्राप्त करना और प्रारम्भ करना अपवाद-तटस्थ है। मैनुअल ऑब्जेक्ट पूल को प्रयुक्त करना सरल है लेकिन उपयोग करना कठिन होता है क्योंकि उन्हें पूल ऑब्जेक्ट के मैन्युअल मेमोरी प्रबंधन की आवश्यकता होती है।

रिक्त पूल संचालन

ऑब्जेक्ट पूल अनुरोध को संरक्षित करने के लिए तीन कूटनीतियों में से एक को नियोजित किया जा सकता है जब पूल में कोई अतिरिक्त वस्तु नहीं होती है।

  1. ऑब्जेक्ट प्रदान करने में विफलता (उपयोगकर्ता को एक त्रुटि देना)।
  2. एक नई वस्तु आवंटित करें, जिससे पूल का आकार विस्तृत हो जाए ऐसा करने वाले पूल समान्यतः आपको उच्च संकेत (कभी उपयोग की जाने वाली वस्तुओं की अधिकतम संख्या) समूह का प्रयोग करने की स्वीकृति देते हैं।
  3. थ्रेड (कंप्यूटर विज्ञान) में, एक पूल उपयोगकर्ता को तब तक ब्लॉक कर सकता है जब तक कि कोई अन्य थ्रेड किसी ऑब्जेक्ट को पूल में वापस नहीं कर देता है।

हानि

यह सुनिश्चित करने के लिए ध्यान रखा जाना चाहिए कि पूल में वापस की गई वस्तुओं की स्थिति वस्तु के अगले उपयोग के लिए एक सुरक्षित स्थिति में वापस आ जाए, अन्यथा वस्तु उपयोगकर्ता द्वारा अप्रत्याशित स्थिति में हो सकती है जिससे यह विफल हो सकती है। पूल ऑब्जेक्ट्स को रीसेट करने के लिए उपयोगकर्ता नहीं उत्तरदायी है जटिल रूप से स्टेल स्थिति वाली वस्तुओं से पूर्ण ऑब्जेक्ट पूल को कभी-कभी ऑब्जेक्ट "सेसपूल" कहा जाता है और इसे एक प्रतिमान के रूप में माना जाता है।

स्टेल स्थिति सदैव एक ऑब्जेक्ट पूल नहीं हो सकती है यह जोखिम युक्त हो जाती है जब यह वस्तु को अप्रत्याशित रूप से प्रयुक्त करने का कारण बनता है। उदाहरण के लिए, प्रमाणीकरण विवरण का प्रतिनिधित्व करने वाली वस्तु विफल हो सकती है यदि सफलतापूर्वक प्रमाणित डेटा को पुन: उपयोग करने से पहले रीसेट नहीं किया जाता है क्योंकि यह इंगित करता है कि उपयोगकर्ता प्रमाणित है (संभवतः किसी और के रूप में) जब वे नहीं होते हैं। हालाँकि, केवल डिबगिंग के लिए उपयोग किए गए मान को रीसेट करने में विफल होने पर, जैसे कि उपयोग किए गए अंतिम प्रमाणीकरण सर्वर की पहचान मे कोई समस्या नहीं हो सकती है।

वस्तुओं की अपर्याप्त रीसेटिंग सूचना के संरक्षण का कारण बन सकती है। गोपनीय डेटा वाली वस्तुओं (जैसे उपयोगकर्ता की क्रेडिट कार्ड संख्या) को नए ग्राहकों को पास करने से पहले रिक्त किया जाना चाहिए, अन्यथा, डेटा को अनधिकृत पार्टी के सामने प्रकट किया जा सकता है। यदि पूल का उपयोग कई थ्रेड्स द्वारा किया जाता है, तो समानांतर थ्रेड्स को उसी ऑब्जेक्ट के समानांतर में पुन: उपयोग करने से स्थगित करने के लिए साधनों की आवश्यकता हो सकती है। यह आवश्यक नहीं होती है यदि पूल किए गए ऑब्जेक्ट अपरिवर्तनीय या थ्रेड-सुरक्षित होते हैं।

समीक्षा

कुछ प्रकाशन कुछ भाषाओं, जैसे जावा (प्रोग्रामिंग भाषा) के साथ ऑब्जेक्ट पूलिंग का उपयोग करने की अपेक्षा नहीं करते हैं, विशेष रूप से उन वस्तुओं के लिए जो केवल मेमोरी का उपयोग करते हैं और कोई बाहरी संसाधन (जैसे डेटाबेस से डेटा संबंध) नहीं रखते हैं। विरोधी समान्यतः कहते हैं कि गार्बेज़ डेटा (कंप्यूटर विज्ञान) के साथ आधुनिक भाषाओं में वस्तु आवंटन अपेक्षाकृत तीव्र है जबकि ऑपरेटर new केवल दस निर्देशों की आवश्यकता है, क्लासिक new - delete पूलिंग डिज़ाइन में पाई जाने वाली जोड़ी को उनमें से सैकड़ों की आवश्यकता होती है क्योंकि यह अधिक जटिल कार्य करता है। इसके अतिरिक्त, अधिकांश गार्बेज़ संग्राहक लाइव ऑब्जेक्ट संदर्भों का अवलोकन करते हैं, न कि उस मेमोरी को जो ये ऑब्जेक्ट डेटा के लिए उपयोग करते हैं। इसका तात्पर्य यह है कि संदर्भ के बिना किसी भी संख्या में निष्क्रिय वस्तुओं को बहुत कम लागत के साथ नियोजित कर दिया जा सकता है। इसके विपरीत, बड़ी संख्या में अप्रयुक्त वस्तुओं को रखने से गार्बेज़ डेटा की अवधि विस्तृत हो जाती है।[1]

उदाहरण

गो (प्रोग्रामिंग भाषा)

निम्नलिखित गो स्रोत कोड के माध्यम से संसाधन के संरक्षण से बचने के लिए एक निर्दिष्ट आकार (समवर्ती प्रारंभीकरण) के एक संसाधन पूल को प्रारंभिकृत करता है और एक रिक्त पूल की स्थितिे में, उपयोगकर्ता को बहुत अधिक समय तक प्रतीक्षा करने से रोकने के लिए टाइमआउट प्रसंस्करण प्रयुक्त करता है।

// package pool
package pool

import (
	"errors"
	"log"
	"math/rand"
	"sync"
	"time"
)

const getResMaxTime = 3 * time.Second

var (
	ErrPoolNotExist  = errors.New("pool not exist")
	ErrGetResTimeout = errors.New("get resource time out")
)

//Resource
type Resource struct {
	resId int
}

//NewResource Simulate slow resource initialization creation
// (e.g., TCP connection, SSL symmetric key acquisition, auth authentication are time-consuming)
func NewResource(id int) *Resource {
	time.Sleep(500 * time.Millisecond)
	return &Resource{resId: id}
}

//Do Simulation resources are time consuming and random consumption is 0~400ms
func (r *Resource) Do(workId int) {
	time.Sleep(time.Duration(rand.Intn(5)) * 100 * time.Millisecond)
	log.Printf("using resource #%d finished work %d finish\n", r.resId, workId)
}

//Pool based on Go channel implementation, to avoid resource race state problem
type Pool chan *Resource

//New a resource pool of the specified size
// Resources are created concurrently to save resource initialization time
func New(size int) Pool {
	p := make(Pool, size)
	wg := new(sync.WaitGroup)
	wg.Add(size)
	for i := 0; i < size; i++ {
		go func(resId int) {
			p <- NewResource(resId)
			wg.Done()
		}(i)
	}
	wg.Wait()
	return p
}

//GetResource based on channel, resource race state is avoided and resource acquisition timeout is set for empty pool
func (p Pool) GetResource() (r *Resource, err error) {
	select {
	case r := <-p:
		return r, nil
	case <-time.After(getResMaxTime):
		return nil, ErrGetResTimeout
	}
}

//GiveBackResource returns resources to the resource pool
func (p Pool) GiveBackResource(r *Resource) error {
	if p == nil {
		return ErrPoolNotExist
	}
	p <- r
	return nil
}

// package main
package main

import (
	"github.com/tkstorm/go-design/creational/object-pool/pool"
	"log"
	"sync"
)

func main() {
	// Initialize a pool of five resources,
	// which can be adjusted to 1 or 10 to see the difference
	size := 5
	p := pool.New(size)

	// Invokes a resource to do the id job
	doWork := func(workId int, wg *sync.WaitGroup) {
		defer wg.Done()
		// Get the resource from the resource pool
		res, err := p.GetResource()
		if err != nil {
			log.Println(err)
			return
		}
		// Resources to return
		defer p.GiveBackResource(res)
		// Use resources to handle work
		res.Do(workId)
	}

	// Simulate 100 concurrent processes to get resources from the asset pool
	num := 100
	wg := new(sync.WaitGroup)
	wg.Add(num)
	for i := 0; i < num; i++ {
		go doWork(i, wg)
	}
	wg.Wait()
}

सी #

.NET बेस क्लास लाइब्रेरी में कुछ ऑब्जेक्ट हैं जो इस पैटर्न को लागू करते हैं। System.Threading.ThreadPool को आवंटित करने के लिए थ्रेड्स की पूर्वनिर्धारित संख्या के लिए कॉन्फ़िगर किया गया है। जब डेटा को वापस किया जाता हैं तो वे दूसरी गणना के लिए उपलब्ध होते हैं। इस प्रकार, थ्रेड्स के निर्माण की लागत का भुगतान किए बिना थ्रेड्स का उपयोग किया जा सकता है।

निम्नलिखित सी # का उपयोग करके कार्यान्वित ऑब्जेक्ट पूल डिज़ाइन पैटर्न का मूल कोड प्रदर्शित किया जा सकता है। संक्षिप्तता के लिए कक्षाओं के गुणों को सी # 3.0 स्वचालित रूप से कार्यान्वित सिंटैक्स का उपयोग करके घोषित किया जाता है। इन्हें भाषा के पुराने संस्करणों के लिए पूर्ण रूप से परिभाषाओं से परिवर्तित किया जा सकता है। पूल को एक स्थिर वर्ग के रूप में प्रदर्शित किया गया है क्योंकि कई पूलों की आवश्यकता होना असामान्य है। हालाँकि, ऑब्जेक्ट पूल के लिए "इंस्टेंस क्लास" का उपयोग करना समान रूप से स्वीकार्य होता है।

namespace DesignPattern.Objectpool;

// The PooledObject class is the type that is expensive or slow to instantiate,
// or that has limited availability, so is to be held in the object pool.
public class PooledObject
{
    private DateTime _createdAt = DateTime.Now;

    public DateTime CreatedAt
    {
        get { return _createdAt; }
    }

    public string TempData { get; set; }
}

// The Pool class controls access to the pooled objects. It maintains a list of available objects and a 
// collection of objects that have been obtained from the pool and are in use. The pool ensures that released objects 
// are returned to a suitable state, ready for reuse. 
public static class Pool
{
    private static List<PooledObject> _available = new List<PooledObject>();
    private static List<PooledObject> _inUse = new List<PooledObject>();

    public static PooledObject GetObject()
    {
        lock (_available)
        {
            if (_available.Count != 0)
            {
                PooledObject po = _available[0];
                _inUse.Add(po);
                _available.RemoveAt(0);
                return po;
            }
            else
            {
                PooledObject po = new PooledObject();
                _inUse.Add(po);
                return po;
            }
        }
    }

    public static void ReleaseObject(PooledObject po)
    {
        CleanUp(po);

        lock (_available)
        {
            _available.Add(po);
            _inUse.Remove(po);
        }
    }

    private static void CleanUp(PooledObject po)
    {
        po.TempData = null;
    }
}

ऊपर दिए गए कोड में, पूल ऑब्जेक्ट में उस समय के लिए गुण होते हैं जब इसे बनाया गया था और दूसरा, जिसे उपयोगकर्ता द्वारा संशोधित किया जा सकता है, पूल में वापस प्रारम्भ किए जाने पर रीसेट किया जाता है। यह दिखाया गया है CleanUp प्रक्रिया, किसी वस्तु को प्रारम्भ करने पर, यह सुनिश्चित करने से पहले कि पूल से फिर से अनुरोध किया जा सकता है यह एक निश्चित स्थिति में ही संभव होता है।

जावा

जावा java.util.concurrent.ExecutorService और अन्य संबंधित वर्गों के माध्यम से थ्रेड पूल पैटर्न का समर्थन करता है। कार्यान्वयन सेवा में एक निश्चित संख्या में "मूल" कोड होते हैं जिन्हें कभी नहीं छोड़ा जाता है। यदि सभी कोड मुक्त हैं तो सेवा अतिरिक्त कोड की अनुमत संख्या आवंटित करती है जिन्हें बाद में छोड़ दिया जाता है यदि निश्चित समाप्ति समय के लिए उपयोग नहीं किया जाता है। यदि अधिक थ्रेड्स की स्वीकृति नहीं है, तो कार्यों को पंक्ति में रखा जा सकता है। अंत में, यदि यह पंक्ति बहुत लंबी हो सकती है तो अनुरोध करने वाले थ्रेड को निलंबित करने के लिए इसे कॉन्फ़िगर किया जा सकता है।

public class PooledObject {
	public String temp1;
	public String temp2;
	public String temp3;
	
	public String getTemp1() {
		return temp1;
	}
	public void setTemp1(String temp1) {
		this.temp1 = temp1;
	}
	public String getTemp2() {
		return temp2;
	}
	public void setTemp2(String temp2) {
		this.temp2 = temp2;
	}
	public String getTemp3() {
		return temp3;
	}
	public void setTemp3(String temp3) {
		this.temp3 = temp3;
	}
}
public class PooledObjectPool {
	private static long expTime = 6000;//6 seconds
	public static HashMap<PooledObject, Long> available = new HashMap<PooledObject, Long>();
	public static HashMap<PooledObject, Long> inUse = new HashMap<PooledObject, Long>();
	
	public synchronized static PooledObject getObject() {
		long now = System.currentTimeMillis();
		if (!available.isEmpty()) {
			for (Map.Entry<PooledObject, Long> entry : available.entrySet()) {
				if (now - entry.getValue() > expTime) { //object has expired
					popElement(available);
				} else {
					PooledObject po = popElement(available, entry.getKey());
					push(inUse, po, now); 
					return po;
				}
			}
		}

		// either no PooledObject is available or each has expired, so return a new one
		return createPooledObject(now);
	}	
	
	private synchronized static PooledObject createPooledObject(long now) {
		PooledObject po = new PooledObject();
		push(inUse, po, now);
		return po;
    }

	private synchronized static void push(HashMap<PooledObject, Long> map,
			PooledObject po, long now) {
		map.put(po, now);
	}

	public static void releaseObject(PooledObject po) {
		cleanUp(po);
		available.put(po, System.currentTimeMillis());
		inUse.remove(po);
	}
	
	private static PooledObject popElement(HashMap<PooledObject, Long> map) {
		 Map.Entry<PooledObject, Long> entry = map.entrySet().iterator().next();
		 PooledObject key= entry.getKey();
		 //Long value=entry.getValue();
		 map.remove(entry.getKey());
		 return key;
	}
	
	private static PooledObject popElement(HashMap<PooledObject, Long> map, PooledObject key) {
		map.remove(key);
		return key;
	}
	
	public static void cleanUp(PooledObject po) {
		po.setTemp1(null);
		po.setTemp2(null);
		po.setTemp3(null);
	}
}

यह भी देखें

टिप्पणियाँ

  1. 1.0 1.1 Goetz, Brian (2005-09-27). "Java theory and practice: Urban performance legends, revisited". IBM. IBM developerWorks. Archived from the original on 2012-02-14. Retrieved 2021-03-15.

संदर्भ

बाहरी संबंध