DWScript是否支持多线程?

9

我想知道DWScript是否能够在脚本内部使用线程,因为有些引擎不会同步访问其内部数据结构。


-1 这个问题可以通过阅读文档、DWScript项目网站首页、网络搜索等方式轻松解答。在提问之前请先做出一些努力。 - David Heffernan
1
如果答案那么容易找到,那我肯定已经跳过它好几次了,否则我也不会发帖问问题了。 - FHannes
4
@david:如果每个人都好好读一下文档,Stack Overflow 就不会存在了 :) - Wouter van Nifterick
你的问题很难猜测。"在脚本中使用线程"并不明显。你是指编译、运行时上下文还是在一个脚本内部(没有S)?越明确越好。例如,你可能会问到"什么是TThread的DWS等效项?"。正如我在答案中所述,你将得到确切的答案:没有 - DWS脚本是单线程执行堆栈。 - Arnaud Bouchez
2个回答

5
Arnaud提出了以下要点:
  • 每个编译器实例一次只能从一个线程调用。您可以同时在多个线程中调用多个编译器实例,并且一个特定的编译器实例可以由多个线程使用,前提是每次只有一个线程使用它。
  • 每个已编译的程序可以有多个执行,每个执行都可以在自己的线程中运行。此外,可以通过多个线程使用特定的执行,前提是每次只有一个线程使用它。
  • 每个执行都有其自己的变量空间和堆栈,对象实例位于堆上,理论上可以在执行之间共享,但没有锁定机制,但您可以自己创建。
  • 脚本引擎在使用向其公开的类或函数(无论是通过TdwsUnit、RTTI等方式)时不执行任何同步或锁定,因此在运行脚本执行时,请确保仅公开线程安全的内容(对于RTTI尤其要小心,因为很多RTL和VCL本身就不是线程安全的)

运行多个脚本执行类似于在Delphi中拥有多个线程,但每个新执行不仅具有自己的堆栈(如Delphi线程),还具有自己的变量空间(在Delphi中,它有点像您在每个地方都有“thread var”)。DWScript执行不必在其自己的线程中运行,它们可以在线程之间移动,或者在较少数量的线程中轮询和使用(唯一的限制是每次只有一个线程使用每个执行,如上所述)。

因此,没有任何阻止您公开一个函数,该函数将在脚本函数中生成线程(和相应的执行),但跨执行的通信不会通过共享变量进行(就像您可能会在Delphi中尝试做的那样),但必须通过您自己公开的函数(或外部变量)、返回值(使用“evaluate”方法,参见单元测试)、“共享”对象实例或“全局变量”进行。

通过“全局变量”,我指的是在dwsGlobalVarsFunctions.pas中定义的函数,可用于跨执行数据交换。要激活它们,只需在项目的某个位置使用“uses dwsGlobalVarsFunctions”即可。

它们公开了一组Read/WriteGlobalVar函数,允许在同一Delphi进程中运行的所有脚本执行中存储和检索命名变量,并且从线程的角度来看,这些读取和写入是“原子”的。


1
很高兴在SO上有DWS的“教父”(或新爸爸)! :) - Arnaud Bouchez
当TdwsProgramExecution对象在一个线程中被执行时,另一个线程能够安全地调用TdwsProgramExecution.EndProgram吗? - FHannes
不可以,但是你可以调用Stop方法来实现(如果你是通过Execute()执行的话,也可以手动使用BeginProgram/RunProgram)。这将导致脚本在其控制下的最早机会中止,即如果您的脚本正在运行Delphi函数,则只有在从该函数返回后才会停止。EndProgram会进行清理工作,并且应该从执行线程中调用。 - Eric Grange

4

甚至不需要打开DWS文档。 :)

只需看看Eric在StackOverflow上的回答

例如,[DWS]现在能够对单个编译脚本进行多个线程安全执行,而旧代码库则建立在一个编译脚本一次只能由一个线程执行的限制之上。

简而言之:

  • DWS编译器不是线程安全的:您必须在一个线程内创建执行堆栈(不能共享编译器实例,每个编译器实例需要一个线程);
  • 如果每个线程使用一个执行实例,则DWS执行是线程安全的:您可以在多个线程中运行相同的编译脚本;
  • 据我所知,线程间通信不可用,但如果需要同步,可以使用Delphi代码。

当然,这里是DWS线程安全的官方文档页面

现在,对于给定的IdwsProgram,您可以拥有任意数量的程序执行,每个执行将仅使用其堆栈内存,编译的表达式树是共享的。这两个新接口都使用引用计数内存管理。

1
阅读这段内容后,我意识到我已经知道了这个,但除非我错了,它并没有完全回答我的问题... 我不想在多个线程中运行相同的脚本,我想在单个脚本内运行多个线程... - FHannes
1
据我所知,就目前而言,根据执行类的实现,这是不可能的,因为它是按设计来的。没有TThread或类似的东西。唯一的可能性是为每个线程运行多个脚本(当然可以),然后尝试在脚本之间进行IPC或互斥,就像我在第三点中写的那样:从头开始没有可用的线程间通信。我更倾向于推荐一个无状态架构,通过Delphi类提供一些共享数据结构(例如使用RTTI公开到DWS)。 - Arnaud Bouchez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接