讨论与说明:
参数化模型有多种实现方式,如SW,CATIA,MS,invent,FC等,但要实现服务化,
首先得支持外程序调用它这个软件接口,打开模型,解析出参数来,再将参数映射到网页或其他软件的插件上,用户修改参数,再驱动调用的接口来修改模型。常用的比如我们用VB程序调用ACAD的接口来处理dwg文件。
其次,服务器上是否需装这个软件?SW,CATIA,MS,invent,FC。比如我在服务器上用网络编程语言go来调用wps打开excel表格,服务器上就得安装wps才行,如果服务器是linux系统呢?所以服务器上需要装软件来解析模型是个麻烦。而FC不用。直接用我写的几行Python编译为exe文件 点这里,放服务器上。再用go调用即可解析FC模型,并用参数修改模型 点这里
所以目前FC这个路线是走通的,才值得花力气生产参数化模型。FC还有个强大的FreecadCmd,任意的python代码或FC宏文件,都可以用freecadcmd来运行,即我们在界面上操作,记录下来的python代码,都可以在这个freecadcmd里运行,没有障碍。
而SW,CATIA,MS,invent等需软件开发人员验证后才知道能否走“服务”这个路线。
第三就是服务并发能力,即ch会上说的,同时100个人来改同一个模型,能同时调用接口修改模型吗?之前我调用mathcad参数化计算书,mathcad就没办法一个计算书同时被100个人修改,也没办法同时运算100个计算书,大家得排队 点这里。所以参数化到服务化至少得考虑这几点。

针对第三点,测试代码如下:
无并发情况下,串行执行,将一个模型修改一个参数并导出glb格式,再串行执行10次花费的时间是22s
并发情况下,同时执行10次,花费时间是5.3s
执行20次的情况对应的是无并发为44.8s,并发是8.6s
Intel(R)Core(TM)i9-10900KCPU@_3.70GHz\10——CPU是20核测试结果

package main

import (
    "context"
    "fmt"
    "bytes"
    "os/exec"
    "sync"
    "time"
    // "github.com/sourcegraph/conc"
)

// 无并发执行主程序,串行执行
func main() {
    start := time.Now()
    values := []string{"200", "300", "400", "500", "600", "700", "800", "900", "1000", "1100"}

    for _, url := range values {
        convertfc2(url)
    }

    elapsed := time.Since(start)
    fmt.Println(elapsed) // 22.3215616s
}

// 并发执行主程序
func main_back2() {
    start := time.Now()
    wg := &sync.WaitGroup{}
    values := []string{"200", "300", "400", "500", "600", "700", "800", "900", "1000", "1100"}
    ctx, cancel := context.WithCancel(context.Background())

    for _, url := range values {
        wg.Add(1)
        subCtx := context.WithValue(ctx, favContextKey("url"), url)
        go convertfc(subCtx, wg)
    }

    go func() {
        // time.Sleep(time.Second * 1)
        time.Sleep(1)
        cancel()
    }()

    wg.Wait()

    elapsed := time.Since(start)
    fmt.Println(elapsed) // 5.3394626s
}

// 无并发修改参数导出模型
func convertfc2(parameter string) {
    arg := []string{"-i", "d:\\goroutetest.fcstd", "-o", "d:\\" + parameter + ".glb", "-p", parameter}
    fmt.Println("-----convertfc--arg-------", arg)
    cmd := exec.Command("D:/convertfc.exe", arg...)

    var stdout, stderr bytes.Buffer
    cmd.Stdout = &stdout
    // cmd.Stderr = os.Stderr
    cmd.Stderr = &stderr
    err := cmd.Run()
    outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
    fmt.Printf("out:\n%s\n err:\n%s\n", outStr, errStr)
    if err != nil {
        fmt.Printf("cmd.Run() failed with %s\n", err)
    }
}

// 并发修改参数导出模型
func convertfc(ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()
    url, _ := ctx.Value(favContextKey("url")).(string)
    for {
        select {
        case <-ctx.Done():
            fmt.Printf("stop getting url:%s\n", url)
            return
        default:
            arg := []string{"-i", "d:\\goroutetest.fcstd", "-o", "d:\\" + url + ".glb", "-p", url}
            fmt.Println("-----convertfc--arg-------", arg)
            cmd := exec.Command("D:/convertfc.exe", arg...)

            var stdout, stderr bytes.Buffer
            cmd.Stdout = &stdout
            // cmd.Stderr = os.Stderr
            cmd.Stderr = &stderr
            err := cmd.Run()
            outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
            fmt.Printf("out:\n%s\n err:\n%s\n", outStr, errStr)
            if err != nil {
                fmt.Printf("cmd.Run() failed with %s\n", err)
            }
        }
    }
}