Ada beberapa fungsi dalam package time
yang bisa dimanfaatkan untuk menunda atau mengatur jadwal eksekusi sebuah proses dalam jeda waktu tertentu.
Fungsi ini digunakan untuk menghentikan program sejenak. time.Sleep()
bersifat blocking, statement dibawahnya tidak akan dieksekusi sampai pemberhentian usai. Contoh sederhana penerapan bisa dilihat pada kode berikut.
package main
import "fmt"
import "time"
func main () {
fmt.Println("start")
time.Sleep(time.Second * 4)
fmt.Println("after 4 seconds")
}
Hasilnya, tulisan "start"
muncul, lalu 4 detik kemudian tulisan "after 4 seconds"
muncul.
Selain untuk blocking proses, fungsi time.Sleep()
ini bisa dimanfaatkan untuk membuat scheduler sederhana, contohnya seperti berikut, scheduler untuk menampilkan pesan halo setiap 1 detik.
for true {
fmt.Println("Hello !!")
time.Sleep(1 * time.Second)
}
Fungsi ini sedikit berbeda dengan time.Sleep()
. Fungsi time.NewTimer()
mengembalikan objek bertipe *time.Timer
yang memiliki property C
yang bertipe channel.
Cara kerja fungsi ini: setelah jeda waktu yang ditentukan sebuah data akan dikirimkan lewat channel C
. Penggunaan fungsi ini harus diikuti dengan statement untuk penerimaan data dari channel C
.
Untuk lebih jelasnya silakan perhatikan kode berikut.
var timer = time.NewTimer(4 * time.Second)
fmt.Println("start")
<-timer.C
fmt.Println("finish")
Statement var timer = time.NewTimer(4 * time.Second)
mengindikasikan bahwa nantinya akan ada data yang dikirimkan ke channel timer.C
setelah 4 detik berlalu. Baris kode <-timer.C
menandakan penerimaan data dari channel timer.C
. Karena penerimaan channel sendiri sifatnya adalah blocking, maka statement fmt.Println("finish")
baru akan dieksekusi setelah 4 detik.
Hasil program di atas adalah tulisan "start"
muncul, lalu setelah 4 detik tulisan "finish"
muncul.
Fungsi time.AfterFunc()
memiliki 2 parameter. Parameter pertama adalah durasi timer, dan parameter kedua adalah callback nya. Callback tersebut akan dieksekusi jika waktu sudah memenuhi durasi timer.
var ch = make(chan bool)
time.AfterFunc(4*time.Second, func() {
fmt.Println("expired")
ch <- true
})
fmt.Println("start")
<-ch
fmt.Println("finish")
Hasil dari kode di atas, tulisan "start"
muncul kemudian setelah 4 detik berlalu, tulisan "expired"
muncul.
Didalam callback terdapat proses transfer data lewat channel, menjadikan tulisan "finish"
akan muncul tepat setelah tulisan "expired"
muncul.
Beberapa hal yang perlu diketahui dalam menggunakan fungsi ini:
- Jika tidak ada serah terima data lewat channel, maka eksekusi
time.AfterFunc()
adalah asynchronous (tidak blocking). - Jika ada serah terima data lewat channel, maka fungsi akan tetap berjalan asynchronous hingga baris kode dimana penerimaan data channel dilakukan. Proses blocking nya berada pada baris kode penerimaan channel.
Kegunaan fungsi ini mirip seperti time.Sleep()
. Perbedaannya adalah, fungsi timer.After()
akan mengembalikan data channel, sehingga perlu menggunakan tanda <-
dalam penerapannya.
<-time.After(4 * time.Second)
fmt.Println("expired")
Tulisan "expired"
akan muncul setelah 4 detik.
Selain fungsi-fungsi untuk keperluan timer, Go juga menyediakan fungsi scheduler (yang disini kita sebut sebagai ticker).
Cara penggunaan ticker cukup mudah, buat objek ticker baru menggunakan time.NewTicker()
isi argument dengan durasi yang diinginkan. Dari objek tersebut kita bisa akses properti .C
yang merupakan channel. Setiap durasi yang sudah ditentikan, objek ticker akan mengirimkan informasi date-time via channel tersebut.
package main
import (
"fmt"
"time"
)
func main() {
done := make(chan bool)
ticker := time.NewTicker(time.Second)
go func() {
time.Sleep(10 * time.Second) // wait for 10 seconds
done <- true
}()
for {
select {
case <-done:
ticker.Stop()
return
case t := <-ticker.C:
fmt.Println("Hello !!", t)
}
}
}
Pada contoh di atas bisa dilihat, selain ticker disiapkan juga variabel channel done
. Variabel ini kita gunakan untuk mengontrol kapan ticker harus di stop.
Cara kerja program di atas: teknik for
- select
pada channel digunakan untuk mengecek penerimaan data dari channel done
dan ticker.C
. By default, channel ticker.C
akan menerima kiriman data setiap N duration yang dimana pada kode di atas adalah 1 detik (lihat argumen inisialisasi objek ticker).
Data yang dikirimkan via channel ticker.C
adalah data date-time kapan event itu terjadi. Pada kode di atas, setiap ada kiriman data via channel tersebut kita tampilkan.
Sebelum blok kode perulangan for
, bisa kita lihat ada goroutine baru di-dispatch, isinya adalah mengirim data ke channel done
setelah 10 detik. Data tersebut nantinya akan diterima oleh blok kode for
- select
, dan ketika itu terjadi, method .Stop()
milik objek ticker dipanggil untuk menonaktifkan scheduler pada ticker tersebut.
Jadi, selama 10 detik, di setiap detiknya akan muncul pesan halo.
Berikut merupakan contoh penerapan timer dan goroutine. Program di bawah ini adalah program tanya-jawab sederhana. Sebuah pertanyaan muncul dan user harus menginputkan jawaban dalam waktu tidak lebih dari 5 detik. Jika 5 detik berlalu dan belum ada jawaban, maka akan muncul pesan time out.
OK langsung saja, mari kita buat programnya, pertama, import package yang diperlukan.
package main
import "fmt"
import "os"
import "time"
Buat fungsi timer()
, nantinya fungsi ini dieksekusi sebagai goroutine. Di dalam fungsi timer()
terdapat blok kode jika waktu sudah mencapai timeout
, maka sebuah data dikirimkan lewat channel ch
.
func timer(timeout int, ch chan<- bool) {
time.AfterFunc(time.Duration(timeout)*time.Second, func() {
ch <- true
})
}
Siapkan juga fungsi watcher()
. Fungsi ini juga akan dieksekusi sebagai goroutine. Tugasnya cukup sederhana, yaitu menerima data dari channel ch
(jika ada penerimaan data, berarti sudah masuk waktu timeout), lalu menampilkan pesan bahwa waktu telah habis.
func watcher(timeout int, ch <-chan bool) {
<-ch
fmt.Println("\ntime out! no answer more than", timeout, "seconds")
os.Exit(0)
}
Terakhir, buat implementasi di fungsi main()
.
func main() {
var timeout = 5
var ch = make(chan bool)
go timer(timeout, ch)
go watcher(timeout, ch)
var input string
fmt.Print("what is 725/25 ? ")
fmt.Scan(&input)
if input == "29" {
fmt.Println("the answer is right!")
} else {
fmt.Println("the answer is wrong!")
}
}
Ketika user tidak menginputkan apa-apa dalam kurun waktu 5 detik, maka akan muncul pesan timeout, lalu program dihentikan.