2012-08-01 13 views
8

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

public static <T> T execute(Callable<T> task, int tries, int waitTimeSeconds, int timeout) 
    throws InterruptedException, TimeoutException, Exception { 

    Exception lastThrown = null; 
    for (int i = 0; i < tries; i++) { 
     try { 
      final Future<T> future = new FutureTask<T>(task); 
      return future.get(timeout, TimeUnit.SECONDS); 
     } catch (TimeoutException ex) { 
      lastThrown = ex; 
     } catch (ExecutionException ex) { 
      lastThrown = (Exception) ex.getCause(); 
     } 
     Thread.sleep(TimeUnit.SECONDS.toMillis(waitTimeSeconds)); 
    } 
    if (lastThrown == null) { 
     lastThrown = new TimeoutException("Reached max tries without being caused by some exception. " + task.getClass()); 
    } 
    throw lastThrown; 
} 

उत्तर

5

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

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

तो, यह देखते हुए कि आप एक ExecutorService है तो आप उसे कॉल कर सकते हैं:

Future<T> future = yourExecutor.submit(task); 

Future.get (timeout) कि समय समाप्ति के लिए इंतजार और अंततः TimeoutException के साथ वापसी भले ही कार्य बिल्कुल शुरू कर दिया कभी नहीं किया होगा, उदाहरण के लिए यदि निष्पादक पहले से ही अन्य काम करने में व्यस्त है और उसे मुफ्त धागा नहीं मिल रहा है। तो, आप कभी भी काम करने का मौका दिए बिना 5 बार कोशिश कर सकते हैं और सेकेंड का इंतजार कर सकते हैं। यह आपकी अपेक्षा की जा सकती है या नहीं भी हो सकती है, लेकिन आमतौर पर यह नहीं है। शायद आपको इसे टाइमआउट देने से पहले शुरू करने के लिए इंतजार करना चाहिए।

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

भले ही आप इसे रद्द कर दें, जब तक कि कॉल करने योग्य "ठीक से लिखा नहीं गया" हो, यह कुछ समय तक चल रहा है। कोड के इस हिस्से में आप इसके बारे में कुछ भी नहीं कर सकते हैं, बस ध्यान रखें कि जावा में कोई अन्य धागा क्या कर रहा है, और अच्छे कारणों से कोई धागा "वास्तव में रुक सकता है"।

हालांकि मुझे लगता है कि आपके कार्य अधिकतर नेटवर्क से संबंधित होंगे, इसलिए इसे थ्रेड बाधा के लिए सही ढंग से प्रतिक्रिया करनी चाहिए।

मैं आमतौर पर एक अलग रणनीति का उपयोग इस तरह की स्थितियों है:

  1. मैं सार्वजनिक स्थिर टी अमल (प्रतिदेय कार्य इंट maxTries, पूर्णांक का समय समाप्त), तो कार्य, कोशिश करता की अधिकतम संख्या (संभावित 1 लिखते थे), अधिकतम कुल टाइमआउट ("मुझे अधिकतम 10 सेकंड में कोई जवाब चाहिए, इससे कोई फर्क नहीं पड़ता कि आप कितनी बार कोशिश करते हैं, 10 सेकंड या कुछ भी नहीं")
  2. मैं कार्य को सक्रिय करना शुरू करता हूं, इसे निष्पादक को देता हूं, और फिर भविष्य को कॉल करता हूं। प्राप्त करें (टाइमआउट/प्रयास)
  3. यदि मुझे परिणाम मिलता है, तो इसे वापस करें। अगर मुझे अपवाद मिलता है, तो फिर से प्रयास करें (बाद में देखें)
  4. यदि मुझे टाइमआउट मिलता है, तो मैं भविष्य को रद्द नहीं करता, बल्कि मैं इसे एक सूची में सहेजता हूं।
  5. मैं जांचता हूं कि बहुत अधिक समय बीत चुका है, या बहुत से रिट्रीज़ हैं। उस स्थिति में मैं सूची में सभी वायदा रद्द कर देता हूं और अपवाद फेंक देता हूं,
  6. अन्यथा, मैं चक्र, कार्य को फिर से निर्धारित करता हूं (पहले के साथ समानांतर में)।
  7. देखें बिंदु 2
  8. यदि मुझे कोई परिणाम नहीं मिला है, तो मैं सूची में भविष्य की जांच करता हूं, शायद पिछले स्पॉन्डेड कार्य में से एक ऐसा करने में कामयाब रहा।

अपने कार्यों को मान लिया जाये कि (अन्यथा कोई रास्ता फिर से प्रयास करना, के रूप में मुझे लगता है कि वे कर रहे हैं) एक बार से अधिक क्रियान्वित किया जा सकता है, नेटवर्क सामान के लिए मैंने पाया इस समाधान बेहतर काम करने के लिए।

मान लीजिए कि आपका नेटवर्क वास्तव में बहुत व्यस्त है, आप नेटवर्क कनेक्शन के लिए पूछते हैं, प्रत्येक 20 रिट्री 2 सेकंड देते हैं। चूंकि आपका नेटवर्क व्यस्त है, 20 सेकंड में से कोई भी कनेक्शन 2 सेकंड में कनेक्शन प्राप्त करने का प्रबंधन नहीं करता है। हालांकि, 40 सेकंड तक चलने वाला एकल निष्पादन डेटा को कनेक्ट और प्राप्त करने का प्रबंधन कर सकता है। यह एक ऐसे व्यक्ति की तरह है जब नेट धीमा हो जाता है, जब पृष्ठ धीमा हो जाता है, तो यह कोई अच्छा नहीं होगा, क्योंकि हर बार ब्राउज़र को शुरुआत से ही शुरुआत करना पड़ता है।

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

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

1

धागा, जिन पर आपका execute इतना समय के लिए अवरुद्ध कर देगा कहा जाता है। सुनिश्चित नहीं है कि यह आपके लिए सही है या नहीं। मूल रूप से, कार्यों के इन प्रकार के लिए, ScheduledExecutorService best.You एक काम अनुसूची और समय निर्दिष्ट कर सकते हैं। ScheduledThreadPoolExecutor

पर एक नज़र डालें
संबंधित मुद्दे