For the parser part, I was really hoping for a PEG example. Because Nim has a native PEG module, and I have not yet manage to understands PEGs really.
Well, I am only at page 198 yet -- will there come some more information about message exchange between threads? Some months ago I was thinking about Nim threads which needs the ability to terminate before completion. One example would be a chess engine thread, which searches for a best move, but has to terminate when human opponent becomes impatient. I think that can be done with channels, but I have no feeling for the best Nim solution...
Listing 6.13, for line in filename.lines: You have exchanged the identifiers file and filename. [EDIT!!!] No, it is only a bit confusing, the lines proc takes indeed a file name as parameter. Identifiers file and filename are a bit confusing when not reading carefully, maybe use filename and path? I still wonder why getCurrentDir() is necessary, can lines() proc only work with absolute paths? Back to Listing 6.14, do you really think that the assignments like "pageTitle.setLen(0)" and "countViews = 0" before calling the parseUtils procs make sense? I had not that expectation, now after looking at parseUtils docs I still do not expect that, but I have not looked at the source code yet. And, while I am still logged in, one more note to Listing 6.14: The text for bullet number 1 is not very easy understandable at that point, I would remove it. You explain it much better below on page 200. Generally you may talk simple about var parameters, not about ref parameters. Andreas called it var parameter in tutorial and manual, and only says that it is a hidden pointer. The term ref may confuse beginners here.
Summary, "Using spawn and the threadpool module create lightweight threads." Strange wording, maybe "TO create"
Page 186: "Save the code in Listing 6.4 as listing3.nim then compile and run it." Please put a , before then, or use word AND instead of then. Generally I would repeat that phrase not that often.
Page 201: "Without that flag the execution time of the application will be significantly slower." The words time and slower makes no sense together!
[EDIT]
Final words: I think the most interesting chapter so far, and mostly well written. And channels are covered also at the end! The comparison of a Nim channel with a FIFO makes it clear that it can be used only for one direction, one thread is writing, one is reading. That was not really clear from Nim documentation, in early days I assumed that I could exchange data between two threads in both directions with only one channel. But now it is clear that I need two!
Last remark:
"Using the threads module to create heavyweight threads."
"Using spawn and the threadpool module create lightweight threads."
Earlier it was my feeling that treads of threads module and threadpool are basically similar with similar "weight". But threadspools keeps always a collection of threads ready, which can be used. While threads module has to create and destroy threads, which may be expensive. When you talk about heavyweight threads and lightweight threads and when they really exist with different weights, then I wonder why lightweight threads work for threadspool, but not for threads module.
in early days I assumed that I could exchange data between two threads in both directions with only one channel. But now it is clear that I need two!
Question: Could 2 threads deadlock if they communicate via 2 channels?
Sorry it took me so long to reply.
For the parser part, I was really hoping for a PEG example. Because Nim has a native PEG module, and I have not yet manage to understands PEGs really.
The reason I didn't explain PEGs is because I don't think that many people are familiar with them. This chapter's focus is concurrency, so talking about parsing was already quite a detour. Explaining PEGs would have been far too much.
Identifiers file and filename are a bit confusing when not reading carefully, maybe use filename and path?
Those identifiers are not correct. I could use file and path I guess.
I still wonder why getCurrentDir() is necessary, can lines() proc only work with absolute paths?
It's good to be explicit. Indeed, lines assumes current working directory.
Back to Listing 6.14, do you really think that the assignments like "pageTitle.setLen(0)" and "countViews = 0" before calling the parseUtils procs make sense
Yes, because those variables need to be reset. Otherwise you could potentially get an old result.
Listing 6.14: The text for bullet number 1 is not very easy understandable at that point, I would remove it. You explain it much better below on page 200
You mean the following one?
The variables in which the parsed tokens are stored are passed by reference, this is more efficient because new strings do not have to be allocated for each call to parse.
I like to explain each of the problematic lines of code in those code annotations, then explain it in more detail below. I would rather not remove it as I think it's good to repeat such explanations, even if one is less clear than the other (it might be the other way around for someone else).
The term ref may confuse beginners here.
I think that many programmers are familiar with the term "reference" as it is the term that is used in the context of Java.
Summary, "Using spawn and the threadpool module create lightweight threads."
Indeed, a mistake on my part. Will fix.
Page 186: "Save the code in Listing 6.4 as listing3.nim then compile and run it." Please put a , before then, or use word AND instead of then. Generally I would repeat that phrase not that often.
Thanks, will fix.
Page 201: "Without that flag the execution time of the application will be significantly slower." The words time and slower makes no sense together!
You're right, it does sound a bit weird. Replaced "slower" with "higher".
Final words: I think the most interesting chapter so far, and mostly well written.
Thank you :)
Earlier it was my feeling that treads of threads module and threadpool are basically similar with similar "weight". But threadspools keeps always a collection of threads ready, which can be used. While threads module has to create and destroy threads, which may be expensive. When you talk about heavyweight threads and lightweight threads and when they really exist with different weights, then I wonder why lightweight threads work for threadspool, but not for threads module.
As far as I know, the threadpool module manages the heavyweight threads for you, only running a limited number of them and therefore keeping resource usage to a minimum. This means that you can call spawn thousands of times without worrying about high memory usage. But calling createThread thousands of times would quickly result in high memory usage.
Could 2 threads deadlock if they communicate via 2 channels?
Pretty sure that would be possible, yes.
As far as I know, the threadpool module manages the heavyweight threads for you, ...
Yes, that was my impression before, and it would be nice if you could add that explanation into chapter 6, I think it is more clear and more correct.
For PEGs -- I have learned some basics already, consulting wikipedia and some other papers. My feeling is, that PEGs may indeed have some advantages, for example when one has to find matching brackets in a string. And we have a pure Nim PEGs module, so I think I will continue learning PEGs...