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.