Golang đại pháp – 1.6 Lấy thông tin từ URL với concurrency
Go
50
golang
49
White

nhaancs viết ngày 05/01/2018

Bài viết được đăng tải đầu tiên tại: http://nhaancs.com/golang-dai-phap-1-6-lay-thong-tin-tu-url-voi-concurrency

golang dai phap

Một trong những tính năng thú vị nhất của Go là Concurrency, đây là 1 chủ đề lớn và sẽ được phân tích kỹ hơn trong các phần sau, phần này chúng ta sẽ tìm hiểu sơ qua về 2 thành phần của Go concurrencygoroutinechannel.

Ví dụ tiếp theo (file fetchall.go) có chức năng giống như ví dụ của phần 1.5. Nhưng ví dụ này có thể lấy nội dung của nhiều url cùng lúc. Vì vậy tổng thời gian thực thi của chương trình sẽ không nhiều hơn thời gian lấy nội dung của url có thời gian lâu nhất. Chúng ta không quan tâm tới response mà chỉ report kích thức và thời gian thực thi.

// Lấy nội dung của tất cả url song song và in ra màn hình kích thước và thời gian tải của chúng
package main

import (
    "fmt"
    "io"
    "io/ioutil"
    "net/http"
    "os"
    "time"
)

func main() {
    start := time.Now()
    ch := make(chan string)

    for _, url := range os.Args[1:] {
        go fetch(url, ch) // start a goroutine
    }

    for range os.Args[1:] {
        fmt.Println(<-ch) // receive from channel ch 
    }

    fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())
}

func fetch(url string, ch chan<- string) {
    start := time.Now()

    resp, err := http.Get(url)
    if err != nil {
        ch <- fmt.Sprint(ch) // send to channel ch 
        return 
    }

    nbytes, err := io.Copy(ioutil.Discard, resp.Body)
    resp.Body.Close();
    if err != nil {
        ch <- fmt.Sprintf("While reading %s: %v", url, err)
        return
    }

    secs := time.Since(start).Seconds()
    ch <- fmt.Sprintf("%2fs %7d %s", secs, nbytes, url)
}

Chạy chương trình:

$ go build fetchall.go

$ ./fetchall https://google.com https://facebook.com http://nhaancs.com

0.658505s   12592 https://google.com
1.399599s   42135 http://nhaancs.com
1.772521s  347317 https://facebook.com
1.77s elapsed

Goroutine là một hàm có thể chạy đồng thời với các hàm khác. Channel sinh ra dùng để giao tiếp giữa hai goroutines, bao gồm gửi và nhận dữ liệu (theo devblog.dwarvesf.com). Về bản chất thì hàm main chạy trong một goroutine và câu lệnh go tạo ra một goroutine khác.

Function main tạo ra một string channel với hàm make. Cứ mỗi tham số truyền vào lệnh go ở đầu vòng lặp for range sẽ tạo ra một goroutine mới chạy hàm fetch để lấy nội dung của url bằng http.Get một cách bất đồng bộ. io.Copy đọc nội dung body của response và xoá đi bằng cách gửi tới stream ioutil.Discard và trả về kích thước body và thông tin lỗi nếu có.

Khi có kết quả trả về, hàm fetch gửi thông tin tóm tắt gồm size, time, url vào channel ch. Vòng lặp range loop thứ hai trong main nhận và hiển thị các thông tin này.

Khi một goroutine gửi hay nhận thông tin từ channel, nó sẽ bị khoá (goroutine đó sẽ dừng chương trình của nó lại) cho đến khi một goroutine khác cũng nhận hay gửi thông tin tương ứng từ goroutine bị khoá. Trong ví dụ này, mỗi hàm fetch gửi một giá trị (ch <- expression) vào channel ch và hàm main nhận tất cả các giá trị đó và hiển thị ra màn hình.

Bài tập cho bạn:

Exercise 1.10: Tìm một web site tạo ra lượng data lớn, chạy hàm fecthall 2 lần xem thời gian report về có thay đổi hay không. Bạn có cùng nhận được một nội dung giống nhau mỗi lần không? Chỉnh sửa fetchall để in kết quả response ra file cho tiện kiểm tra.

Exercise 1.11: Thử truyền vào fetchall một danh sách tham số dài hơn như danh sách một triệu website trên alexa.com. Chương trình sẽ như thế nào nếu có 1 website không response.

Reference: The Go Programming Language

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

nhaancs

11 bài viết.
4 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
2 0
Bài viết được đăng tải đầu tiên tại: http://nhaancs.com/golangdaiphap23khaibaobien/ Khai báo với từ khoá var tạo ra 1 biến có kiểu xác định, gán...
nhaancs viết 6 tháng trước
2 0
Bài viết liên quan
White
16 0
Crawl dữ liệu Crawl là một vấn đề hay gặp trong quá trình làm software. Ví dụ lấy tin tức, tin giảm giá, vé xem phim... là những dạng của crawl. Mộ...
Thach Le viết hơn 2 năm trước
16 0
White
9 2
Makefile thực hiện một số thao tác thường dùng trong Go Khi làm project Go mình thường tạo một file Makefile dạng này: Lưu ý nhớ thay thành tên m...
Huy Trần viết 2 năm trước
9 2
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
11 bài viết.
4 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!