*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.

Reply via email to