Dear all,
I would like to use parallel and am running into unexpected compilation problems, apparently because the procedure in question returns a string. An artificial example is given below. For this I took the normally perfectly fine working code (if it returns a float) for efficiently computing pi from the docs and made it return a string:
import strutils, math, threadpool
{.experimental: "parallel".}
proc term(k: float): string =
var f = 4 * math.pow(-1, k) / (2*k + 1)
result = $f
proc pi(n: int): float =
var ch = newSeq[string](n+1)
parallel:
for k in 0..ch.high:
ch[k] = spawn term(float(k))
#for k in 0..ch.high:
# result += ch[k]
result = ch[0]
echo formatFloat(pi(5000))
This obviously doesn't do anything, but it does trigger the compilation error:
Error: type mismatch: got <FlowVar[system.string]> but expected 'TaintedString = string'
I don't quite understand what's going on. Using TaintedString and switching taintMode on or not, doesn't change anything.
Could someone please help?
Many thanks, Andreas
I think your code should not compile at all in its current form, as result = ch[0] is an incompatible assignment, string to float.
Generally parallel processing is restricted in Nim currently with default GC, as each thread has its own heap ans so passing data is difficult. I never used parallel in the last years, so I can not really help. But see post below, so problem seems to be known, and things will improve soon with new --gc:arc
import strutils, math, threadpool
{.experimental: "parallel".}
proc term(k: float): string =
var f = 4 * math.pow(-1, k) / (2*k + 1)
result = $f
proc pi(n: int): string =
var ch = newSeq[string](n+1)
parallel:
for k in 0..ch.high:
ch[k] = ^ spawn term(float(k))
result = ch.join
echo pi(5000)Just need to make the math make sense.
Flowvar is like a Promise on JavaScript or like a Future on Python, but for parallel. Like a container type thingy, to put other thingies inside, as they pop into existance at run time.
import random
import strutils
import threadpool
{.experimental: "parallel".}
proc genString(length: int): string =
for i in 1..length:
result.add(char(rand(int('a') .. int('z'))))
proc genSentence(n: int): string =
var ch = newSeq[string](n)
#var ch = newSeq[FlowVar[string]](n)
parallel:
for k in 0..ch.high:
let r = rand(3..9)
ch[k] = spawn genString(r)
#ch[k] = genString(r)
#for k in 0..ch.high:
# result = result & ^ch[k]
# result = result & " "
result = ch.join(" ")
echo genSentence(10) & "."
The compilation error is:
Error: type mismatch: got <FlowVar[system.string]> but expected 'TaintedString = string'
The code works fine if I don't use parallel (but do use FlowVars and read with ^)
Many thanks, Andreas
Because the size of an int/float is known at compile-time, the compiler can optimize the FlowVar away and instead tell the spawned proc where to write the result. This is not possible for string.