Closed baywet closed 3 years ago
I do not fully understand what you're trying to accomplish by "async work". But, function invoked as gorountines cannot return a Boolean; they must return nothing. I do not understand why you are considering channels here. If you want to execute a bunch of parallel operations and find out when they all complete, then a channel could be used for this or perhaps a WaitGroup is what you need. Or, maybe just a slice with results in it and each goroutines fills in its index of the slice?
Also is this "async work" part of your API that you're exposing to customers? If so, this sounds VERY suspect. Or, is this some SDK function that internally executes a bunch of parallel operations and aggregates their responses?
By async work here I mean a network bound operation. In other languages the methods return a future /promise /task so the work is at worst deferred to a thread pool, at best to a co-processor and the main thread is not blocked and can process other things while waiting for the response. In all the other languages so far, the only place we needed this is when the generated sdk actually executes the request. The advantage of returning the task construct is that it allows the consumer to either chain or parellalize multiple tasks. For example if the consumer needs to get 3 objects from the Api that are not interdependent, returning the task makes it easier to run these requests concurrently instead of sequentially. Another example is the ability to chain this task with an higher level one to increase throughput, a web service is a good example of such case. I hope that clarifies the point?
Yes, I understand what you're saying but this doesn't apply to Go. Go supports goroutines INSTEAD OF aysnc operations. So, libraries just have methods in them which offer a synchronous programming model but, under the covers the goroutines are asynchronous already. This is one of the reasons why Go is a great/simpler language compared to many others: Go developers NEVER thinks about async operations (but they are happening anyway).
So if I understand things right, consumers would expect the sdk to be synchronous and blocking. But they'd wrap things with go routines at the appropriate level?
If one of the methods returns a value they need for subsequent instructions, is it common practice to wrap things in local functions that'd be executed by a routine? Kind of like the callback way of handling promises in JavaScript?
Yes, Go devs expect SDK methods to be synchronous and blocking. THEY can wrap them if they so desire (usually they do not desire this).
If a method returns a value that customer code needs to use (which is VERY common), then they just write the code to use it after the method call - just like in any programming language. They would not wrap anything at all.
Ok thank you so much for gong through this. It clarifies a lot of things including the absence of a promise /task construct. It's intriguing that a language used to build so many web apps made the decision to handle things mostly in a blocking synchronous way. The web hosts must be relying on thread pools for every incoming web request. Regardless this was super helpful!
You are thinking that a goroutine is the same thing as a thread. This is not the case. The Go runtime multiplexes the potentially millions of goroutines on the threads. When a goroutine blocks, the runtime switches the thread to a different goroutine. The programming model is synchronous but the io operations are asynchronous. It's just that developers get this for free. This is one of go's major strengths as compared to other languages.
-- Jeffrey Richterhttps://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fjeffrichter%2F&data=04%7C01%7Cjeffreyr%40microsoft.com%7C22479ac85e5243cd5daf08d93164b830%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637595130922909659%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=0eSlDrJljhzGEmilUf5wTrxyhPVnAQ%2BksbnPiH4lJBs%3D&reserved=0 (see Architecting Distributed Cloud Appshttps://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Faka.ms%2FRichterCloudApps&data=04%7C01%7Cjeffreyr%40microsoft.com%7C22479ac85e5243cd5daf08d93164b830%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637595130922919618%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=00QzMoRaDwCfjHo9hRw2h%2BO90PLM5mr9LRgALfzsXMg%3D&reserved=0 & Designing HTTP APIshttps://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D9Ng00IlBCtw%26list%3DPL9XzOCngAkqs4m0XdULJu_78nM3Ok3Q65%26index%3D1&data=04%7C01%7Cjeffreyr%40microsoft.com%7C22479ac85e5243cd5daf08d93164b830%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637595130922919618%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=7IX%2F2xnJDM6lR%2F26iR8c6Y9HJL2cKw%2B0cXTBd8oMQ2s%3D&reserved=0)
From: Vincent Biret @.> Sent: Tuesday, August 10, 2021 5:31:40 PM To: microsoft/kiota @.> Cc: Jeffrey Richter @.>; Mention @.> Subject: Re: [microsoft/kiota] Go generation async anti-pattern (#468)
Ok thank you so much for gong through this. It clarifies a lot of things including the absence of a promise /task construct. It's intriguing that a language used to build so many web apps made the decision to handle things mostly in a blocking synchronous way. The web hosts must be relying on thread pools for every incoming web request. Regardless this was super helpful!
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fmicrosoft%2Fkiota%2Fissues%2F468%23issuecomment-896404551&data=04%7C01%7C%7C36075ec1d46a434485e708d95c5f637a%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637642387018863778%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=p1qBWPwPLP2ZTgIbcub6nu%2BW0vrL%2Fa5e0mGPc5BFC3Y%3D&reserved=0, or unsubscribehttps://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FAARLJP6H6TQBNH53SSVWTHTT4HAGZANCNFSM5B4VQVCQ&data=04%7C01%7C%7C36075ec1d46a434485e708d95c5f637a%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637642387018873733%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=17blBH%2Bu18uMNlVC12dvTQc7o7VAo%2BGrzveZx2%2FEThU%3D&reserved=0.
oh ok, that makes sense, so go routines are effectively similar to Tasks/Promises/Futures, except they are handled at the higher runtime level and cannot be returned. Thanks again!
update on this, in #716 while implementing a request adapter service (and other things) I removed the callback anti-pattern to leave things to a synchronous API surface. This is still WIP, but we're making progress. Thanks again for the early feedback
Pending on #413
Go does not have a predefined construct for async/concurrent work like Promise/Task/Futures in other languages. We're currently generating async methods using a callback signature (returning a func), this approach is not super convenient for callers.
Feedback from @JeffreyRichter on an internal thread:
you should absolutely not provide async APIs in a Go library as this causes harm (additional resource consumption & perf slowdowns) and zero benefit whatsoever – this is just not how Go and its goroutines work
A few alternatives to consider for async work:
Logging this issue so we can discuss the course of actions. So far Kiota has taken the approach of only delivering Async APIs. We might deliver sync APIs as well for languages that provide async constructs, but those sync APIs would only be a wrapper around the async ones.
CC @darrelmiller on the architecture aspects. Should we allow platforms/languages to differ on that aspect?