加快FsCheck任意生成
Speed up FsCheck Arbitrary generation
我正在编写一些生成器和一个 Arbitrary,但速度太慢(另请参阅 GC 编号)。我想我的代码有错误,但我不知道在哪里。或者我的方法(map2 (fold)
)是"weird"?
发电机:
type Generators () =
static let notAllowed = Array.append [| '0'..'9' |] [| '\n'; '\r'; '['; ']'; '/'; |]
static let containsInvalidValues (s : string) = s.IndexOfAny(notAllowed) <> -1
static member positiveIntsGen() = Arb.generate<PositiveInt> |> Gen.map int
static member separatorStringGen() =
Arb.generate<NonEmptyString>
|> Gen.suchThat (fun s -> s.Get.Length < 5 && not (s.Get |> containsInvalidValues))
任意:
let manyNumbersNewLineCustomDelimiterStrInput =
Gen.map2 (fun (ints : int[]) (nes : NonEmptyString) ->
Array.fold (fun acc num ->
if num % 2 = 0 then acc + "," + num.ToString()
else if num % 3 = 0 then acc + "\n" + num.ToString()
else acc + "\n" + num.ToString()) ("//[" + nes.Get + "]\n") ints )
(Generators.array12OfIntsGen())
(Generators.separatorStringGen())
|> Arb.fromGen
配置有 MaxTest = 500
,完成需要大约 5 分钟。
输出(使用#timer):
StrCalcTest.get_When pass an string that starts with "//[" and contains "]\n" use the multicharacter value between them as separator-Ok, passed 500 tests.
Real: 00:07:03.467, CPU: 00:07:03.296, GC gen0: 75844, gen1: 71968, gen2: 4
在没有实际测试任何东西的情况下,我的猜测是有问题的部分是这样的:
Arb.generate<NonEmptyString>
|> Gen.suchThat (fun s -> s.Get.Length < 5 && not (s.Get |> containsInvalidValues))
这意味着您将生成字符串并过滤掉所有满足特定条件的字符串。但是如果条件太严格,FsCheck 可能需要生成非常多的字符串,直到你真正得到一些通过测试的字符串。
如果您可以表达规则以便生成字符串,以便生成的所有内容都是有效字符串,那么我认为它应该更快。
例如,您能否生成一个数字 n
(用于字符串长度),后跟 n
类型 char
的值(满足您的条件),然后附加它们形成分隔符字符串? (我认为 FsCheck 的 gen { .. }
计算可能是一种很好的写法。)
我正在编写一些生成器和一个 Arbitrary,但速度太慢(另请参阅 GC 编号)。我想我的代码有错误,但我不知道在哪里。或者我的方法(map2 (fold)
)是"weird"?
发电机:
type Generators () =
static let notAllowed = Array.append [| '0'..'9' |] [| '\n'; '\r'; '['; ']'; '/'; |]
static let containsInvalidValues (s : string) = s.IndexOfAny(notAllowed) <> -1
static member positiveIntsGen() = Arb.generate<PositiveInt> |> Gen.map int
static member separatorStringGen() =
Arb.generate<NonEmptyString>
|> Gen.suchThat (fun s -> s.Get.Length < 5 && not (s.Get |> containsInvalidValues))
任意:
let manyNumbersNewLineCustomDelimiterStrInput =
Gen.map2 (fun (ints : int[]) (nes : NonEmptyString) ->
Array.fold (fun acc num ->
if num % 2 = 0 then acc + "," + num.ToString()
else if num % 3 = 0 then acc + "\n" + num.ToString()
else acc + "\n" + num.ToString()) ("//[" + nes.Get + "]\n") ints )
(Generators.array12OfIntsGen())
(Generators.separatorStringGen())
|> Arb.fromGen
配置有 MaxTest = 500
,完成需要大约 5 分钟。
输出(使用#timer):
StrCalcTest.get_When pass an string that starts with "//[" and contains "]\n" use the multicharacter value between them as separator-Ok, passed 500 tests.
Real: 00:07:03.467, CPU: 00:07:03.296, GC gen0: 75844, gen1: 71968, gen2: 4
在没有实际测试任何东西的情况下,我的猜测是有问题的部分是这样的:
Arb.generate<NonEmptyString>
|> Gen.suchThat (fun s -> s.Get.Length < 5 && not (s.Get |> containsInvalidValues))
这意味着您将生成字符串并过滤掉所有满足特定条件的字符串。但是如果条件太严格,FsCheck 可能需要生成非常多的字符串,直到你真正得到一些通过测试的字符串。
如果您可以表达规则以便生成字符串,以便生成的所有内容都是有效字符串,那么我认为它应该更快。
例如,您能否生成一个数字 n
(用于字符串长度),后跟 n
类型 char
的值(满足您的条件),然后附加它们形成分隔符字符串? (我认为 FsCheck 的 gen { .. }
计算可能是一种很好的写法。)