知方号

知方号

Golang Worker Pool and Concurrency Tutorial

13. October 2023 | No Comments

The best “Application programmers” are cultured to focus on business requirements and typically don’t always factor in the need for concurrency — and that’s the way it should be. We don’t think of concurrency first — we think of “business requirements first”.

Often the complexities involved in writing concurrent code are abstracted inside a Go library or a third-party package (e.g. HTTP server handlers) but it is not always the case. Now and then, there is a requirement to scale up functionality in a way that cannot leverage existing libraries. Every programmer must know to write concurrent code — a functionally correct code is useless if it cannot scale up — and vice versa.

In this blog post, I will provide step-by-step instructions to make “sequential” code “concurrent.” I will start with a sequential code and then refactor it to make it concurrent. This is how I do it in real life — I focus on business functionality first, write a sequential correct version of my code and then refactor to make it more concurrent.

Addressing the business functionality — The sequential code

Step number one is to write sequential code right. Let us encapsulate business functionality into one function.

businessFunctionality() responseBreaking down the business functionality

Come up with some intelligent way to break the functionality into small chunks. You cannot parallelize it if you cannot modularize it.

For exploring data, an option to explore data based on dates is worth exploring. For example, a business functionality can explore data from Jan 1 to Dec 31. This can be broken into 365 (or 366) jobs — where each job takes care of exploring data for one day.

func businessFunctionalityJob(startTime, endTime time.Time) JobResponse{ ...}

And the overall flow will be something like this:

func businessFunctionality() response{ jobStartTime := //startTime jobEndTime := //endTime jobWindow := 24 * time.Hour var jobResponses []JobResponse for currentTime := jobStartTime; currentTime.Before(jobEndTime); currentTime = jobStartTime.Add(jobWindow) { jobResponses = append(jobResponses, businessFunctionality(jobStartTime, jobEndtime)) } return combineResponses(jobResp)}

Alternatively, you can look at breaking the business functionality with some number range

func businessFunctionalityJob(start, end int64) response { ...}Golang Developer Jobs

More generically,

type JobInput struct { startTime time.Time endTime time.Time}type JobResponse struct { //keeping this empty for this example. Real-world will be more complex.}type Response struct { finalOutput string}func businessFunctionality() Response { var jobInputs []JobInput //Create job input for each job var jobResponses []JobResponse for _, jobInput := range jobInputs { jobResponses = append(jobResponses, businessFunctionalityJob(jobInput)) } return combineResponses(jobResponses)}func combineResponses(jobResponses []JobResponse) Response { return Response{finalOutput: "Well done!!"}}func businessFunctionalityJob(jobInput JobInput) JobResponse { return JobResponse{}}func main() { fmt.Println(businessFunctionality().finalOutput)}

Making it parallel

So far, we have broken down the functionality but have not made any progress in improving performance. We can easily make it parallel by starting multiple go routines.

Read the full Tutorial There is no ads to display, Please add someTweet

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。