क्या अंतराल पर दोहराव वाले कार्य करने का कोई तरीका है?


148

क्या गो में दोहराए गए पृष्ठभूमि कार्यों को करने का एक तरीका है? मैं Timer.schedule(task, delay, period)जावा में कुछ ऐसा सोच रहा हूं । मुझे पता है कि मैं एक गोरोइन के साथ ऐसा कर सकता हूं Time.sleep(), लेकिन मैं कुछ ऐसा चाहूंगा जो आसानी से बंद हो जाए।

यहाँ मुझे क्या मिला, लेकिन मुझे बदसूरत लगता है। क्या कोई क्लीनर / बेहतर तरीका है?

func oneWay() {
    var f func()
    var t *time.Timer

    f = func () {
        fmt.Println("doing stuff")
        t = time.AfterFunc(time.Duration(5) * time.Second, f)
    }

    t = time.AfterFunc(time.Duration(5) * time.Second, f)

    defer t.Stop()

    //simulate doing stuff
    time.Sleep(time.Minute)
}

3
अपने उदाहरण में time.Duration (x) का उपयोग करने के लिए धन्यवाद। हर उदाहरण मुझे मिल सकता है एक हार्डकोड int और यह शिकायत करता है जब आप एक int (या फ्लोट) var का उपयोग करते हैं।
माइक ग्रेफ

@ माइकग्राफ आप उस समय कर सकते हैं t := time.Tick(time.Duration(period) * time.Second)जब पीरियडint
फ्लोरियनरोसेनबर्ग

यह समाधान बहुत अच्छा लगता है, IMO। esp। अगर यू केवल बाहरी समय के बजाय f () कहते हैं। बाद में। उन मामलों के लिए बहुत अच्छा है, जहां आप काम पूरा होने के बाद x सेकंड में काम करना चाहते हैं, बनाम एक निरंतर अंतराल पर।
ल्यूक डब्ल्यू

जवाबों:


240

फ़ंक्शन time.NewTickerएक चैनल बनाता है जो एक आवधिक संदेश भेजता है, और इसे रोकने का एक तरीका प्रदान करता है। इसे कुछ इस तरह से प्रयोग करें (अप्राप्त):

ticker := time.NewTicker(5 * time.Second)
quit := make(chan struct{})
go func() {
    for {
       select {
        case <- ticker.C:
            // do stuff
        case <- quit:
            ticker.Stop()
            return
        }
    }
 }()

आप कार्यकर्ता को quitचैनल बंद करके रोक सकते हैं close(quit):।


9
ओपी क्या चाहता है, इसके आधार पर उत्तर गलत है। यदि ओपी एक आवधिक निष्पादन चाहता है, भले ही कार्यकर्ता कितने समय का उपयोग करता है, तो आपको do stuffएक नियमित रूप से चलना होगा या अगले कर्मचारी को तुरंत निष्पादित करना होगा (जब 5 सेकंड से अधिक की आवश्यकता हो)।
नीमो

2
IMO, आपको बस close(quit)तब चाहिए जब आप अनुसूचक को रोकना चाहते हैं।
डस्टिन

3
टिकर काम करना बंद कर देता है, लेकिन गोरोइन को कभी भी कचरा एकत्र नहीं किया जाएगा।
पॉल हैंकिन

4
@SteveBrisk डॉक्टर को देखें । यदि चैनल बंद हो गया है तो एक रीड बस सफल हो जाएगा और आप ऐसा नहीं चाह सकते हैं।
नीमो

10
@ bk0, टाइम चैनल "बैकअप" नहीं है (प्रलेखन कहता है "यह अंतरालों को समायोजित करता है या धीमी रिसीवर के लिए टिक बनाने के लिए ड्रॉप करता है")। दिए गए कोड वही करते हैं जो आप कहते हैं (अधिकतम एक कार्य पर चलता है); यदि कार्य में लंबा समय लगता है, तो अगले आह्वान में देरी होगी; कोई म्यूटेक्स की आवश्यकता नहीं है। यदि इसके बजाय यह वांछित है कि एक नया कार्य हर अंतराल शुरू हो जाता है (भले ही पिछले समाप्त नहीं हुआ है) तो बस उपयोग करें go func() { /*do stuff */ }()
डेव सी

26

कैसे कुछ के बारे में

package main

import (
    "fmt"
    "time"
)

func schedule(what func(), delay time.Duration) chan bool {
    stop := make(chan bool)

    go func() {
        for {
            what()
            select {
            case <-time.After(delay):
            case <-stop:
                return
            }
        }
    }()

    return stop
}

func main() {
    ping := func() { fmt.Println("#") }

    stop := schedule(ping, 5*time.Millisecond)
    time.Sleep(25 * time.Millisecond)
    stop <- true
    time.Sleep(25 * time.Millisecond)

    fmt.Println("Done")
}

खेल का मैदान


3
A time.Ticker, उस time.Afterजगह से बेहतर है जहाँ आप कार्य को शेड्यूल बनाम निष्पादन के बीच अनियंत्रित अंतर पर रखना पसंद करेंगे।
डस्टिन

5
@ डस्टिन और यह बेहतर है यदि आप कार्यों के अंत और शुरुआत के बीच एक निश्चित अंतराल के साथ काम करना चाहते हैं। न तो सबसे अच्छा है - यह दो अलग-अलग उपयोग के मामले हैं।
ओपन स्कूल

`` `// अवधि बीतने का इंतजार करने के बाद और फिर दिए गए चैनल पर वर्तमान समय // भेजता है। // यह न्यूटीमर (d) .C के बराबर है। // अंतर्निहित टाइमर कचरा संग्रहकर्ता द्वारा पुनर्प्राप्त नहीं किया जाता है // जब तक कि टाइमर आग नहीं। यदि दक्षता एक चिंता का विषय है, तो न्यूटिमर `` का उपयोग कैसे करें इस कथन के बारे में:If efficiency is a concern, use NewTimer
ली

23

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

अर्थात

package main

import "fmt"
import "time"

func main() {
    go heartBeat()
    time.Sleep(time.Second * 5)
}

func heartBeat() {
    for range time.Tick(time.Second * 1) {
        fmt.Println("Foo")
    }
}

खेल का मैदान


19

इस लाइब्रेरी को देखें: https://github.com/robfig/cron

नीचे के रूप में उदाहरण:

c := cron.New()
c.AddFunc("0 30 * * * *", func() { fmt.Println("Every hour on the half hour") })
c.AddFunc("@hourly",      func() { fmt.Println("Every hour") })
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty") })
c.Start()

3

इस सवाल का एक व्यापक जवाब अक्सर ओगम में इस्तेमाल होने वाले लेगो ईंट दृष्टिकोण पर विचार कर सकता है, और जेसीएसपी के माध्यम से जावा समुदाय को पेशकश की गई है । इस विचार पर पीटर वेल्च द्वारा एक बहुत अच्छी प्रस्तुति है

यह प्लग-एंड-प्ले दृष्टिकोण गो के लिए सीधे अनुवाद करता है, क्योंकि गो एक ही कम्युनिकेटिंग सीक्वेंशियल प्रोसेस फंडामेंटल्स का उपयोग करता है जैसा कि ओक्टम करता है।

इसलिए, जब दोहराए जाने वाले कार्यों को डिजाइन करने की बात आती है, तो आप अपने सिस्टम को सरल घटकों के डेटाफ्लो नेटवर्क (गोरोइन के रूप में) के रूप में बना सकते हैं जो चैनलों के माध्यम से घटनाओं (यानी संदेश या संकेत) का आदान-प्रदान करते हैं।

यह दृष्टिकोण कंपोजिटल है: छोटे घटकों का प्रत्येक समूह खुद को एक बड़े घटक, विज्ञापन इन्फिनिटम के रूप में व्यवहार कर सकता है। यह बहुत शक्तिशाली हो सकता है क्योंकि जटिल समवर्ती प्रणाली ईंटों को समझने में आसान से बनाई गई हैं।

फुटनोट: वेल्च की प्रस्तुति में, वह चैनलों के लिए ओक्टम सिंटैक्स का उपयोग करता है, जो है ! और ? और ये सीधे गो में ch <- और <-ch के अनुरूप हैं ।


3

मैं निम्नलिखित कोड का उपयोग करता हूं:

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    fmt.Println("\nToday:", now)

    after := now.Add(1 * time.Minute)
    fmt.Println("\nAdd 1 Minute:", after)

    for {
        fmt.Println("test")
        time.Sleep(10 * time.Second)

        now = time.Now()

        if now.After(after) {
            break
        }
    }

    fmt.Println("done")
}

यह अधिक सरल है और मेरे लिए ठीक है।


0

आप किसी भी क्षण में इसे रोकने के लिए चाहते हैं, तो टिकर

ticker := time.NewTicker(500 * time.Millisecond)
go func() {
    for range ticker.C {
        fmt.Println("Tick")
    }
}()
time.Sleep(1600 * time.Millisecond)
ticker.Stop()

आप को रोकने के लिए नहीं करना चाहते हैं यह टिकटिक :

tick := time.Tick(500 * time.Millisecond)
for range tick {
    fmt.Println("Tick")
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.