2011-09-15 15 views
5

पर हास्केल (जीएचसी) में थ्रेडडेले समस्या मैंने जीएचसी में थ्रेडडे फ़ंक्शन के साथ अजीब व्यवहार देखा। मेरी कुछ मशीनों पर कॉनक। निम्नलिखित प्रोग्राम:उबंटू

main = do print "start" 
      threadDelay (1000 * 1000) 
      print "done" 

अपेक्षा के अनुसार 1 सेकंड लेता है। दूसरी ओर, इस कार्यक्रम:

{-# LANGUAGE BangPatterns #-} 
import Control.Concurrent 

main = do print "start" 
      loop 1000 
      print "done" 
    where loop :: Int -> IO() 
     loop !n = 
      if n == 0 
      then return() 
      else do threadDelay 1000 
        loop (n-1) 

, मेरे मशीनों के दो पर चलने के लिए के बारे में 10 सेकंड लेता है की उम्मीद के रूप में यद्यपि अन्य मशीनों पर इसके बारे में 1 सेकंड लेता है,। (मैंने थ्रेडस्कोप से एक स्क्रीन शॉट को संकलित किया है। यहां दिखाया गया है कि प्रत्येक 10 मिलीसेकंड में केवल एक बार गतिविधि होती है: Screenshot of ThreadScope showing that threadDelay of 1 millisecond sleeps for 10 milliseconds.

दूसरी ओर, यहां से एक स्क्रीनशॉट है मेरी मशीनों में से एक से ThreadScope जिस पर कार्यक्रम लेता है 1 सेकंड कुल: Screenshot of ThreadScope showing that threadDelay of 1 millisecond sleeps for about 1 milliseconds.

ऐसा ही एक सी कार्यक्रम:

#include <unistd.h> 
#include <stdio.h> 

int main() { 
    int i; 
    for (i=1; i < 1000; i++) { 
    printf("%i\n",i); 
    usleep(1000); 
    } 
    return 0; 
} 

है सही काम चल रहा है, यानी './a.out समय' की तरह उत्पादन देता है :

1 
2 
... 
999 

real 0m1.080s 
user 0m0.000s 
sys 0m0.020s 

क्या किसी को इससे पहले इस समस्या का सामना करना पड़ा है, और यदि हां, तो यह कैसे तय किया जा सकता है? मैं अपनी सभी मशीनों पर लिनक्स (x86_64) के लिए ghc 7.2.1 चला रहा हूं और उबंटू के विभिन्न संस्करण चला रहा हूं। यह उबंटू 10.04.2 पर बुरी तरह काम करता है, लेकिन 11.04 पर ठीक है।

उत्तर

3

threadDelay एक सटीक टाइमर नहीं है। यह वादा करता है कि आपका धागा कम से कम तक सो जाएगा जब तक कि इसका तर्क कहता है कि यह चाहिए, लेकिन इससे इससे कुछ भी वादा नहीं होता है। यदि आप समय-समय पर कुछ करना चाहते हैं, तो आपको कुछ और उपयोग करना होगा। (मुझे यकीन नहीं है कि, लेकिन संभवतः Unix' realtime alarm signal आपके लिए काम करेगा।)

1

मुझे संदेह है कि आप '-थ्रेडेड' विकल्प के साथ संकलित करना भूल गए हैं। (मुझे लगता है कि एक बार किया था 6.12.3 के लिए, और लगातार 30 मिलीसेकंड धागा देरी की थी।)

+0

मैंने वास्तव में 'थ्रेड वाले' ध्वज के साथ संकलित किया था। – Andreas

1

जैसा कि ऊपर बताया, threadDelay केवल एक गारंटी है, जो यह है कि आप कम से कम जब तक आप का अनुरोध के रूप में इंतजार करेंगे बनाता है। हास्केल के क्रम ओएस

उसके अलावा से विशेष सहयोग प्राप्त नहीं है, यह ओएस से सर्वश्रेष्ठ प्रयास है।

धागे के लिए अपने परिणामों को बेंचमार्क करना उचित हो सकता है। उदाहरण के लिए:

module Main where 
import Control.Concurrent 
import Data.Time 

time op = 
    getCurrentTime >>= \ t0 -> 
    op >> 
    getCurrentTime >>= \ tf -> 
    return $! (diffUTCTime tf t0) 

main :: IO() 
main = 
    let action tm = time (threadDelay tm) >>= putStrLn . show in 
    mapM action [2000,5000,10000,20000,30000,40000,50000] >> 
    return() 

मेरी खिड़कियों बॉक्स पर, यह मेरे देता है:

0.0156098s 
0.0156098s 
0.0156098s 
0.0312196s 
0.0312196s 
0.0468294s 
0.0624392s

इस देरी का कॉम्बो चलता है और getCurrentTime 15.6 मिलीसेकंड का एक संकल्प है। जब मैं 1000 बार 1000 गुना लूप करता हूं, तो मैं 15.6 सेकेंड का इंतजार कर रहा हूं, इसलिए यह थ्रेड के लिए न्यूनतम प्रतीक्षा है।

मेरी Ubuntu बॉक्स पर (11.04, गिरी 2.6.38-11 के साथ), मैं बहुत अधिक से अधिक परिशुद्धता (~ 100us) मिलता है।

यह हो सकता है आप इस कार्यक्रम व्यस्त रख कर समय समस्या से बच सकते हैं, तो हम नहीं संदर्भ दूर स्विच। किसी भी तरह से, मैं सुझाव दूंगा कि आप समय के लिए थ्रेडडे का उपयोग न करें, या कम से कम समय की जांच करें और दिए गए तत्काल तक कोई भी ऑपरेशन करें।

सी के माध्यम से आपकी उच्च परिशुद्धता नींद आपके लिए काम कर सकती है, अगर आप एफएफआई के साथ मिलना चाहते हैं, लेकिन लागत आपको बाध्य धागे (कम से कम अपने टाइमर के लिए) का उपयोग करने की आवश्यकता होगी।