129 likes
·
24.9K reads
27 comments
Great article! I've been used c/c++/c#/java/python for many years, and using go since 2013. All the mentioned lessons I have met before. Thanks for sharing!
I really enjoyed reading your article Sayed Alesawy. Go is not a language I am familiar with but it seems really interesting. Thanks for sharing!
Thank you! Glad you liked it.
Now, Your article made me start learning GO. But I have no experience with strictly typed languages.
That's great! I recommend checking this tutorial: golangbot.com/learn-golang-series along with the go tour here: tour.golang.org/welcome/1 and anything else you need later, there is probably a godoc for it.
nice article by the way...
Thank you! Glad you liked it.
Great! Can't wait for part two
Thank you! Hopefully, I will get to it soon.
Very cool read! I have heard great things about Go. This is a cool overview of some of its functionality. It seems to handle concurrency very well!
Thank you!
Thank you! Yes, Go is really great for writing concurrent applications and it's also blazing fast and doesn't really take that much development time to build, so all in all, quite an awesome language.
As far as I know, in most cases singletons are considered an anti-pattern. It's probably better to explicitly pass *sql.DB object around
I am not really sure why do you think so. I mean my rationale is that you will probably need to do some initialization of some sort, like maybe pass connection configurations or something like that. You will probably do it in an init method or something, then after that you can use the connection variable. Looks like if somebody forgot to init, they will run into problems and here comes the usefulness of having a wrapper method. And if you have a wrapper method and it's not singleton, that will be problematic as well.
I am interested to know why do you think it's an anti pattern or if you have a resource that supports that. Thanks for the thought tho!
Singletons are horrible advice, don't follow that pattern. Anything that creates a static, package level variable is bad.
Care to elaborate on that?
I know there is a somewhat compelling argument against singleton in general. I am not sure how could I replace it tho and get the same effect? I will check the article you mentioned. Thanks for the comment!
Sayed Alesawy Replace it with a regular struct which accepts the dependency on it.
If it gets complex you can write a factory method on the struct.
The approach with channels from (1) looks dubious to me. You have omitted the important part explaining it by clarity, but what is missing is important for understanding of the concept. Maybe it's just me.
You have to call server.Run()
in a goroutine in (4), otherwise your code will block at this method.
Yes, you are correct about 4, it was a typo, I corrected it. Thank you!
About 1, I dunno, might be up to taste but I have seen it in a lot of places and written by people who are go contributors actually. It's definitely less verbose but if you are very familiar with channels, it's as understandable in my opinion.
The idea here is that you only need to open a database connection once. According to go docs, the Open() function returns a connection that is "safe for concurrent use by multiple goroutines and maintains its own pool of idle connections. Thus, the Open function should be called just once. It is rarely necessary to close a DB."
So you can call on the init function on start (there will be no other calls to it at this point) and that's it. You can refer to the docs here: golang.org/pkg/database/sql/#Open
Sayed Alesawy As far as I understand, in this case sql.Open is just for example, which means there could be any other function with indefinite execution time.
I would like to return to the problem stated in paragraph 2 (without init function): ...Consider the case where 2 goroutines are calling the function DBConnection() at the same time. It's possible that the first goroutine reads the value of dbInstance and finds it nil and then proceeds to create a new connection...
Does dbOnce.Do block the rest of the function's calls for the execution time, or just let them pass by and return nil?
Oleksiy Oh, I understand what you mean now. That's a really nice case to think about.
As far as I know, calls to sync.Once won't return until the function f() inside the Do function returns. So if multiple goroutines call it concurrently, they will block waiting until the first call returns, then they will be executed, but of course they won't re-execute Once again.
I wrote this code: play.golang.org/p/ftvpEyhHDio to make sure and try it out. You can try changing the value of Sleep at line 22 to something bigger and you will see that the routines are blocked.
Considering this behavior, I still think it's good for initializations.
Sayed Alesawy Ah, great, then the question is off the table. Yes, I've now studied the Once.Do implementation, it's fun and seems to be specifically designed to lock other calls until the return from the function happens.
Thanks for sharing, we'll especially want people to ensure they understand CSP (tony Hoare) , and know about the go proverbs ( a source of the sharing memory quote: go-proverbs.github.io )
Good video on the topic: youtube.com/watch?v=oV9rvDllKEg
A lot of go problems seem to stem from not understanding how to model their program concurrently
Great Article! Very informative.
Just a quick note, you can’t actually intercept SIGKILL (or SIGSTOP for that matter), I believe you meant SIGTERM or SIGINT in your example in (4).