*Thank you for responding. My response has been placed inline, below.....* On Monday, September 12, 2016 at 8:08:28 AM UTC-4, Tamás Gulácsi wrote: > > > > 2016. szeptember 12., hétfő 7:28:26 UTC+2 időpontban davidmi...@gmail.com > a következőt írta: >> >> *I have two Golang questions that I hope someone could help me out with.* >> >> >> *1) Am I misunderstanding Golang maps?* >> >> >> *I'm trying to translate a project from PHP to Golang for the websockets >> and the concurrency. * >> >> >> *However, I can't do this.....* >> >> >> * var MyArray [string]string* >> >> >> *Instead, I have to do this.....* >> >> >> * var MyMap map[string]string* >> >> >> *However, since the same array (map) would be used at least once for each >> call to the Golang code from the Front End, which occurs any time a user >> sends data to the Back End, I have been led to believe that I would have to >> lock and unlock the map for each use. Wouldn't that essentially break >> concurrency (or at least eliminate its benefits??? No other user's function >> could use this map until the current user's function is done with it. I'd >> be back to "single threaded" again (concurrently speaking). This would >> defeat much of the point in my switching the project from PHP to Golang. To >> maintain concurrency without blocking other users, one would have to avoid >> using maps. Arrays (maps) are central to programming. How does anyone get >> by in Golang without using Maps?????* >> >> >> *For example, if I do the following.....* >> >> >> *func MyFunc (whatever) *map[string]string *{* >> >> >> var MyMap map[string]string >> >> >> * // Do something with the map* >> >> >> * return MyMap* >> >> >> *}* >> >> >> *func CallingFunction (whatever) {* >> >> >> * MyReturnedMap := go MyFunc(whatever)* >> >> >> *}* >> >> >> *.....would I have to lock and unlock the map or are two separate >> instances of the map declared?* >> >> >> *Again, am** I misunderstanding Golang maps?* >> >> >> > Use the lock for as short time as possible: only around get and set > access! Maybe even: > mMu.RLock() > v, ok := m[k] > mMu.RUnlock() > > if ok {... > if v ... > > mMu.Lock() > m[k] = v > mMu.Unlock() > > *That's the exact scenario that would eliminate the purpose of using concurrency whenever a map is used..... All goroutines would have to wait their turn (in some order or another) to use the map. *
*One of the primary benefits of concurrency is that if one procedure gets stuck or slows down, other procedures can keep moving along, evading the bottleneck. Once you throw a shared bottleneck into the concurrent routines, one loses out on the benefit of using concurrent procedures.* *It's like if cars were driving down the highway in two lanes and the lanes merged for just a moment and then separated again into two lanes. If there were no exits before the merge (between the cars approaching the merge and the merge), then using two lanes would be pointless, since they all have to merge with each other anyway at that bottleneck. When they get to the merge point and have to wait their turn. It doesn't matter that they were concurrent (even parallel) before the bottleneck. They might as well have not as been concurrent in the first place! In that case, there would be no merge and everyone could just travel in a straight line at a steady speed! No bottleneck! Notice how there can be two traffic points at a toll on a toll road. The first is when someone takes a long time to pay. The second is the merge after the toll. If the first can be eliminated, splitting the lanes up into multiple toll lanes and then merging them again would only cause traffic and not prevent it. In my scenario, a Golang map would apparently work, not like a toll, but like the merge after the toll.* *It doesn't really matter how long the merge takes or how short a time one locks the map. If it's so fast that it can be done in "single threaded" mode (concurrently speaking) anyway, why use concurrency? The fact that no other procedure can use the map while it is locked potentially forces a full stop on all other procedures waiting to use the map. As just stated, it's as if all such procedures have gone back to "single threaded" mode (concurrently speaking).* *That's not to say that there aren't other potential bottlenecks being evaded by using concurrent routines that do no have the shared map problem, but if one is using locks often or if the map bottleneck is a central part of a procedure's functionality, it seems possible that one might not really be benefiting much from using concurrency in the first place.* > By the way your example does not use the map concurrently, as *MyFunc *will > return a new map. > *This comment might be an answer to my question. * *Also, if yes, then I thank you very much for your answer to this question!* *Please clarify.....* *The map is declared within the goroutine. Since the map is declared within the goroutine, is the scope of the map limited to the goroutine or does the map remain unsafe to use in multiple goroutines? Does the map have to be declared outside of the goroutine, in a "larger" scope, within which the goroutine is called, in order to be unsafe to use in goroutines?* *In other words, are you saying that since the map is declared within a goroutine and not merely accessed by a goroutine (after being declared elsewhere), it remains safe to use without locks, under the circumstances?* *If yes, then Golang would behave as one would expect! That would be a relief. I've been hoping that my concern behind this question comes down to my own misunderstanding of how Golang handles concurrency with maps. * *Also, instead, of being a potential bottleneck under all circumstances, a map might be used to transfer information between goroutines (assuming the coordination was worked out properly), while still being unblocking if declared within the goroutines themselves.* And your code won't even compile! (no "v := go f()" syntax in go). > *Of course it won't compile. It's merely pseudocode. **More reasons it won't compile..... The parameters are invalid (see "whatever") and the MyReturnedMap variable isn't used.* *However, thank you for pointing out that error anyway, though, since **I was unaware that one could not set a variable to a goroutine (as in "v := go f()").* *I've just tried it to confirm what you've said (by trying it) and you appear to be correct. That syntax only appears in my pseudocode, above, not in my actual code.* *I was unaware that this wouldn't be valid syntax. As you could probably tell, I'm pretty new to Golang.* *That said, that part of the code doesn't really affect my question. * > > > > >> *2) Also, how would one build a multidimensional array with a string >> index (or even a map of maps) for something like a large file directory >> where the number of files, folders and levels are unknown at the outset >> (without repeatedly using the append function that apparently uses memory >> on an exponential scale of 2^x)? I've figured out how to do >> map[string]map[string]map[string]string, but one would have to know how >> many levels there would be, in advance, to be able to use something like >> that. Also, when I've tried that, I can't put a string on any level except >> for the last one, since the only data type that any level other than the >> last one will accept is another map! What if the map turns out to be only >> three levels deep for one path and five levels deep for another path?** I've >> tried the following, which I found online, but I can't dynamically add any >> new folders to the directory with any kind of ease. It seems that >> initializing the struct is the only way to get data into the struct without >> declaring a new struct for every manipulation!* >> >> >> *(Below code from >> **http://stackoverflow.com/questions/19080116/golang-tree-like-solution-for-filesystem >> >> <http://stackoverflow.com/questions/19080116/golang-tree-like-solution-for-filesystem>)* >> >> >> package Websocket >> >> import "fmt" >> >> type File struct { >> Name string >> } >> >> type Folder struct { >> Name string >> Files []File >> Folders []Folder >> } >> >> func main() { >> root := Folder{ >> Name: "Root", >> Files: []File{ >> {"One"}, >> {"Two"}, >> }, >> Folders: []Folder{ >> { >> Name: "Empty", >> }, >> }, >> } >> fmt.Printf("Root %#v\n", root) >> } >> >> >> *Given the above, how would i now add another folder to the directory tree. >> Among many other variations, I've tried the following.....* >> >> >> *root.Folders[0].Name = "MyFirstFolder"* >> >> >> *.....but nothing I have tried has worked.* >> >> >> *What I've been trying to do is set up an array that looks like the >> following.....* >> >> >> *MyArray["Number of Sub Items"] = 6* >> >> *MyArray["Type of Sub Items"] = "Folders"* >> >> *MyArray[0] = "Folder 1"* >> >> *MyArray[1]** = "Folder 2"* >> >> *MyArray[2]** = "Folder 3"* >> >> *MyArray[3]** = "Folder 4"* >> >> *MyArray[4]** = "Folder 5"* >> >> *MyArray[6]** = "Folder 6"* >> >> >> *MyArray[3]**["Number of Sub Items"]** = 3* >> >> *MyArray["Type of Sub Items"] = "Folders"* >> >> *MyArray[3][0] = "Folder 1"* >> >> *MyArray[3][1]** = "Folder 2"* >> >> *MyArray[3][2]** = "Folder 3"* >> >> >> *Note that this problem is not exclusive to directory structure. Using >> directory structure is just a simple way to describe the problem I'm having.* >> >> >> *Alternatively**, are there any libraries that can do the above so that I >> don't have to "reinvent the wheel"?* >> >> >> > For not reinventing the wheel, take a look at http.File, FileSystem, and > Dir > *As I said above..... "Note that this problem is not exclusive to directory structure. Using directory structure is just a simple way to describe the problem I'm having."* *I used the "File/Folder" description as an easier way to describe the scenario. I could have used family trees, for example, as well. Any tree structure where a variable could either be a string or another array/map would have been sufficient. I could have also referred to Javascript Objects as well to describe what I was referring to. I am not concerned, specifically, with the system's file structure. * > For using a map: why not use the path (with / as separator) as the key? > *This is not a terrible suggestion. I found a similar suggestion online last night (after I posted here) using ":" between levels. However, before using "workarounds", I'd like to find out how Golang intended developers to accomplish this objective. Multidimensional arrays (and trees) with string indexes are pretty fundamental to programming. For example, just about any recordset returned from a database will be returned with a field (or column) name and value, which would contain a string as the field (or column) name. In that case, it would be helpful to access the data in each row as part of an associative array, while each row would also be a sub row of the larger array containing all of the rows in the recordset. **I figured there must be a way to use them properly in Golang without breaking concurrency.* *Before resorting to using something like ":" or "/" for the key, I'd like to see if there's a "proper" way to accomplish this in Golang first.* > Or implement a tree with pointers, if you really need it. > *Wouldn't implementing a tree with pointers have the same problem as implementing a map? Wouldn't writing to the tree cause other goroutines to see the edited version of the tree, rather than their own, exclusive, version of the map?* *Also, how does one implement a tree using strings as indexes if not by using a map of maps?* > > What are you wishing to accompish? > > *I'd like to accomplish exactly what I've stated. When working with data, I end up having to manipulate many types of [key]item lists, many of which can have sub lists, such as [key][key]item and where [key] is often a string, not an int. This is not a "one case scenario" where an alternate approach would be acceptable (like your file system response). It's a common scenario that I come across that has to be resolved. * *I have been exploring the "append" option, but I am concerned about the exponential doubling of capacity. Wouldn't it have made more sense to have another variable in the function to specify how much should be added on if the capacity has been reached? That parameter could have been either an int, which would indicate how much capacity to add when the limit is reached, or an option, such as "double the existing amount" or "add another set of the initial amount". This last question is mostly a rhetorical question that only the Golang team of developers could probably answer.* *Again, thank you for your response. If I've understood your answer to the first question, then you have sufficiently answered it. Thank you!* *As for the second question, I'm still trying to figure out the best way to solve that problem.* -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.