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

From Vigyanwiki
Revision as of 14:30, 2 March 2023 by alpha>Indicwiki (Created page with "{{for|the article about a general pool|Pool (computer science)}} ऑब्जेक्ट पूल पैटर्न एक सॉफ्टवेयर रचनात्...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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

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

विवरण

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

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

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

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

लाभ

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

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

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

कार्यान्वयन

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

मैनुअल ऑब्जेक्ट पूल को लागू करना सरल है, लेकिन उपयोग करना कठिन है, क्योंकि उन्हें पूल ऑब्जेक्ट के मैन्युअल मेमोरी प्रबंधन की आवश्यकता होती है।

खाली पूलों का संचालन

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

  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;
    }
}

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

जावा

जावा थ्रेड पूल पैटर्न का समर्थन करता है 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.


संदर्भ


बाहरी संबंध