How to do asynchronous programming in Go ?

993 views
Skip to first unread message

Boopathi Rajaa

unread,
Apr 9, 2015, 5:40:46 PM4/9/15
to golan...@googlegroups.com
I'm very much used to JavaScript, so, sorry that this might be biased to JS context.

In JavaScript, for asynchronous calls, we use Promises and Streams. Promises are asynchronous singular primitives analogous to values. Streams are asynchronous plural primitives analogous to a list of values. 

I'm looking to use something like this in Go. Specifically, lazy loading/transforming/calculating some sequence of data.

So with streams in JS, we have an interface close to Unix pipes. So basically, we can do,

```js
SomeReader().pipe(parseJSON()).pipe(getValue('key')).pipe(makeRequest()).pipe(parseResponse()).pipe(process.stdout);
// similar to
// $ readFile | parseJson | getValue key | makeRequest | parseResponse > stdout
```

In Go, I find it difficult to do something like this. I've seen the "io" package that it supports Reader and Writer interface where you can send a buffer and Pipe it. But applying transformations for the values along the way and similar others aren't clear to me. And I ended up using a straight synchronous flow and spawn go routines whenever something can be done concurrently, and wait for them to complete and continue the flow.

One main issue I have is that there are too many `if err != nil { return "", err }`. Where in JS, I define only one error handler in a chain of events. And if one of them breaks it is caught in this handler, and I handle the error here.

```js
somePromise.then(a).then(b).then(c).catch(handleError);
```

I'm not comparing both the languages putting one over another . I just want to learn (from what I've been using already) - the Go way of doing things.

yehezkielbs

unread,
Apr 9, 2015, 8:29:03 PM4/9/15
to golan...@googlegroups.com
It seems correct to do your example synchronously, because after all they are serial tasks. You parseJSON only after you read the data, then you can call getValue only after you have parsed the json string, etc. And then you wrap all of them in a goroutine so your code can do something else.

go func () {
  x := read()
  y := parse(x)
  z := getValue(y)
  ...
}

What's the issue with that?


Cheers,
Yehezkiel Syamsuhadi

Ian Lance Taylor

unread,
Apr 9, 2015, 9:02:46 PM4/9/15
to Boopathi Rajaa, golang-nuts
On Thu, Apr 9, 2015 at 2:40 PM, Boopathi Rajaa <legen...@gmail.com> wrote:
>
> In JavaScript, for asynchronous calls, we use Promises and Streams. Promises
> are asynchronous singular primitives analogous to values. Streams are
> asynchronous plural primitives analogous to a list of values.

In Go, write synchronous code. It's easier to understand. Don't use
Promises.

When you want to run different streams concurrently, use a goroutine.
Send the results back on a channel.


> I'm looking to use something like this in Go. Specifically, lazy
> loading/transforming/calculating some sequence of data.

Look at, for example, http://golang.org/test/chan/sieve1.go for lazy
streams of numbers not divisible by some number.

Ian

fatdo...@gmail.com

unread,
Apr 9, 2015, 9:08:02 PM4/9/15
to golan...@googlegroups.com, legen...@gmail.com
And using channel in that manner would be just like doing promises. So what is it? code synchronously or use channels to implement asynchronous code?

Ian Lance Taylor

unread,
Apr 9, 2015, 9:13:24 PM4/9/15
to AK Willis, golang-nuts, Boopathi Rajaa
On Thu, Apr 9, 2015 at 6:07 PM, <fatdo...@gmail.com> wrote:
> And using channel in that manner would be just like doing promises. So what
> is it? code synchronously or use channels to implement asynchronous code?

Using channels is of course roughly equivalent to promises, but the
use is different in relevant ways. When I say "program synchronously"
I meant don't write code like new Promise(/* do stuff now and report
it later*/). I mean write two different pieces of code, that both
look synchronous, and use channel operations to communicate.

Ian


> On Thursday, April 9, 2015 at 9:02:46 PM UTC-4, Ian Lance Taylor wrote:
>>
>> On Thu, Apr 9, 2015 at 2:40 PM, Boopathi Rajaa <legen...@gmail.com> wrote:
>> >
>> > In JavaScript, for asynchronous calls, we use Promises and Streams.
>> > Promises
>> > are asynchronous singular primitives analogous to values. Streams are
>> > asynchronous plural primitives analogous to a list of values.
>>
>> In Go, write synchronous code. It's easier to understand. Don't use
>> Promises.
>>
>> When you want to run different streams concurrently, use a goroutine.
>> Send the results back on a channel.
>>
>>
>> > I'm looking to use something like this in Go. Specifically, lazy
>> > loading/transforming/calculating some sequence of data.
>>
>> Look at, for example, http://golang.org/test/chan/sieve1.go for lazy
>> streams of numbers not divisible by some number.
>>
>> Ian
>
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Boopathi Rajaa

unread,
Apr 10, 2015, 2:41:48 AM4/10/15
to golan...@googlegroups.com


On Friday, April 10, 2015 at 5:59:03 AM UTC+5:30, yehezkielbs wrote:
It seems correct to do your example synchronously, because after all they are serial tasks. You parseJSON only after you read the data, then you can call getValue only after you have parsed the json string, etc. And then you wrap all of them in a goroutine so your code can do something else.

go func () {
  x := read()
  y := parse(x)
  z := getValue(y)
  ...
}
 
What's the issue with that?

```go
go func(d chan string, e chan error) {
  x, err := read()
  if err != nil {
    e <- err
  }
  y, err := parse(x)
  if err != nil {
    e <- err
  }
  z, err := getValue(y)
  if err != nil {
    e <- err
  }
  d <- z
}(datachannel, errorchannel)
```

This code looks bad. I understand that errors SHOULD be handled and bubbled up to the parent, but here for every line, I'm writing two more lines for error handling. Is there any way to handle error at one place in a chain of events - if the chain breaks, this error handler gets called. 

Boopathi Rajaa

unread,
Apr 10, 2015, 2:52:25 AM4/10/15
to golan...@googlegroups.com, legen...@gmail.com
Ah. Thanks! Exactly what I've been looking for. 
 

Ian

parais...@gmail.com

unread,
Apr 10, 2015, 7:27:37 AM4/10/15
to golan...@googlegroups.com


This code looks bad. I understand that errors SHOULD be handled and bubbled up to the parent, but here for every line, I'm writing two more lines for error handling. Is there any way to handle error at one place in a chain of events - if the chain breaks, this error handler gets called. 
 

By what standard ? Go compels you to deal with errors as soon as they happen or your code will panic sooner or later.

I'm not comparing both the languages putting one over another .

Sure you are. You are comparing a plateform(nodejs) which doesn't allow to write concurrent code with a language that has true concurrency primitives.

You write synchronous code in Go period. As a little exercice , try to write setTimeout and setInterval functions in Go. You will understand how your question makes little sense and how you don't need these 2 functions in Go.

Klaus Post

unread,
Apr 10, 2015, 9:51:35 AM4/10/15
to golan...@googlegroups.com
Hi Boopathi.

As others pointed out, you cannot expect Go to be the same as what you are used to. We could spend hours bashing javascipt, and all the problems that things like promises/callbacks gives, but I am not sure that would help you much.

However, have a look at this. I tried to take your example and make it a bit better looking: http://play.golang.org/p/6QGdgRHL9b

I like this, because I think it is very clear what happens if any stage fails. The error value is always being sent, and we can clearly see when the result is being returned.

I am sure other people can make it even nicer. I hope this helps you.

/Klaus

Boopathi Rajaa

unread,
Apr 10, 2015, 10:00:11 AM4/10/15
to Klaus Post, golan...@googlegroups.com

I've been using go and I really like it. I was just trying to visualize things with what I knew already. That's it and never compare language features. And thanks Klaus for the example. I'm doing this already in my code, and as Ian Lance Taylor suggested, I'm writing different pieces of synchronous code and calling them in go routines. http://golang.org/test/chan/sieve1.go - this example was exactly what I was looking for. 

Thanks all


--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/Nb4E-mjltks/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.

Paul Borman

unread,
Apr 10, 2015, 10:57:32 AM4/10/15
to Boopathi Rajaa, Klaus Post, golang-nuts
Sounds like you are using Communicating Sequential Processes :-)


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

l...@ansync.com

unread,
Apr 10, 2015, 5:30:06 PM4/10/15
to golan...@googlegroups.com
As he mentions, the Node version with promises conveniently returns to a single place when any of the functions errors. The go equivalent would probably be to report to a channel:

  go func(r chan int) {
    x, y, z int
    e error

    x, e = Read()
    if (e) {
      r <- -1
      return
    }
    y, e = Parse()
    if (e) {
      r <- -2
      return
    }
    z, e = GetValue()
    if (e) {
      r <- -3
      return
    }
    r <- z
Reply all
Reply to author
Forward
0 new messages