数据共享,静态变量和管道 [英] Datasharing, static variables and pipes

查看:70
本文介绍了数据共享,静态变量和管道的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,
我一整天都在阅读有关如何在流程之间最佳共享数据的文章/博客.我之前没有机会深入探讨此主题,但我想知道您认为最好的解决方案是解决以下问题.

我正在开发一个使用MEF绑定插件的应用程序.插件(主要是显示为MDI表单的表单)可以根据其需要/提供的内容具有多种接口实现,大型机会检查它们是否已实现,然后满足其需求.
到目前为止,一切正常,可以正常运行.

现在,如果您启动应用程序,它将要求输入有效的登录名(MainFrame),如果登录成功,则用户将存储在MainFrame中.
现在,知道所有可用插件的PluginManager会在激活后将用户传递到插件中.

那行得通,但这是个好方法吗?

我还考虑过要有一个AppEnvironment类,该类使用静态变量共享一些信息,例如User,DataConn-Strings等.
该应用程序大量使用Tasks,因此我使用静态锁定对象保护了在运行时可能会更改的静态变量.

我已经在这里读到了有关静态变量不好的信息.真的是这样吗?

我发现的另一件事是,我可以使用管道在MainFrame及其子窗体之间共享信息.
这不是过量吗?您喜欢/使用管道来满足此类要求吗?

请不要误会我的意思,我不是在寻找一种简单的方法来存档我想要的东西,但是我真的很想以一种精致,优雅的方式在MainFrame及其ChildForms中共享信息.如果我能学到新的东西,那就更好了;)

感谢您的关注,我们将不胜感激:)

欢呼
Andy

Hi all,
I spent my day reading articles/blogs about how to best share data between processes. I haven''t had the opportunity to dive deep into this topic before, but I was wondering what the best solution would be in your opinion to handle the following.

I am developing an application that binds plugins using MEF. Plugins (mostly forms that are displayed as MDI forms) can have multiple interface implementations based on what they need/offer, the mainframe checks if they are implemented and then satisfies their needs.
So far everything is fine, up and running.

Now if you start the app it asks for a valid login (MainFrame) and if the login succeeds the user is stored in the MainFrame.
The PluginManager which knows about all the available plugins now passes the user into the plugin upon activation.

That works, but is it a good approach?

I also thought about having a AppEnvironment class that shares several information like User, DataConn-Strings etc. using static variables.
The App uses Tasks a lot so I secured the static variables that may be changed during runtime using static locking objects.

I already read here about that static variables are bad... Is this really the case?

Another thing that I figured out is that I could use pipes to share information between the MainFrame and its child-forms...
Isn''t this a little bit overdosed? Do you like/use pipes for such requirements?

Don''t get me wrong please, I am not searching for an easy way to archive what I want, but I really like to have a fine, elegant way to share the information within MainFrame and its ChildForms. If I can learn something new, even better ;)

Thanks for your attention, any help is kindly appreciated :)

cheers
Andy

推荐答案

我的第一个问题是:过程"是什么意思?这是真正的进程间通信(在OS方面),还是您在谈论同一应用程序中的子系统交互?我问的原因是因为插件通常以第二种方式实现-在C#中,通常是通过在运行时使用Assembly.Load或Assembly.LoadFrom加载程序集来实现的-如果您实际上是在使用单独的进程(Process.Start),我会需要更多地了解您在做什么,以确保这是正确的方法.

如果您使用的是真正的流程,那么您将只能使用操作系统为您提供的功能;通常称为管道或插座.我通常使用TCP套接字,因为我可以使用已经编写的用于网络通信的类,如果有用,它可以使在网络上拆分系统变得容易,并且因为这是我的经验.但是,任何跨进程通信都将要求您序列化和反序列化传输对象,您将无法共享内存等.

我怀疑你不是这个意思,特别是对于静态变量的引用;我认为您的意思是子系统之间进行通信.在这种情况下,您可以制定适合您确切需求的解决方案.一个基于消息的体系结构是一个很好的起点:模块可以将消息发布到其他模块的队列中(可能只是它们自己和控制中心模块,可能是系统中的任何其他模块;我对此还不了解). ,然后模块处理其消息队列并执行操作.例如,允许用户输入的模块可以验证数据,使用该模块可用的信息对其进行处理,然后向集线器发布一条消息,指出应更新表XYZ中的数据.

这样做的好处是您可以串行流式传输数据控制消息,因此不会出现争用情况数据损坏,但是不必让每个模块都等待所有其他模块(这会破坏UI响应能力).您还可以让中心通知其他模块数据已更新,因此它们应该刷新其视图(有点类似于Observer模式,但在子系统级别).
My first question is: what do you mean by ''process''? Is this really inter-process (in the OS sense) communication, or are you talking about interacting subsystems within the same application? The reason I ask is because plugins are usually implemented in the second way – in C#, usually by loading assemblies at runtime with Assembly.Load or Assembly.LoadFrom – and if you''re actually using separate processes (Process.Start) I would need to know more about what you''re doing to be sure that''s the right approach.

If you''re using genuine processes, you''re limited to what the OS will give you; that''s usually named pipes or sockets. I typically use TCP sockets because I can use classes I already wrote for networked communication, it makes it easy to split the system across a network if that''s useful, and because that''s what I have experience with. Any cross-process communication though will require you to serialise and deserialise transfer objects, you won''t be able to share memory, etc.

I suspect you don''t mean that, particularly with your references to static variables; I think you mean communicating between subsystems. In this case you can craft a solution that fits your exact needs. A good starting point is a message based architecture: modules can post messages on the queue of other modules (possibly just themselves and a controlling hub module, possibly any other module in the system; I don''t know enough to judge on that), and modules process their message queues and do things. For example, a module that allows user entry could validate the data, process it with information that that module has available, and then post a message to the hub saying that data in table XYZ should be updated.

This has the advantage that you can stream data control messages serially, so you won''t get race condition data corruption, but you don''t have to make each module wait on all the others (which kills UI responsiveness). You can also have the hub tell other modules that data is updated so they should refresh their views (a bit like the Observer pattern but on a subsystem scale).


我曾经尝试过管道方法,并且如果您有真正独立的流程,它会很好地工作.和共享内存一样,但是那是在C ++时代.我最终完成的工作似乎是您的需要(插件实际上并未在单独的进程中运行,但也许我错了),我只是提供了一个用于管理容器(袋子,集合,我很快了解到拥有不同的容器是一件很不错的事,并且我还了解了我想抽象化变量"(通常是本机类型,但它可能很复杂).以及输入),以便我可以在值更改时触发事件.这也是进行某些客户端验证的一种很好的机制:该值不能为null,必须在一定范围内,等等,所有这些约束和验证都可以通过setter事件绑定.

因此,简而言之,我的解决方案要求将内存管理(容器)抽象化,并将变量(也称为内存位置)抽象为全类公民Var.

坦率地说,如果我必须跨流程工作,则该概念仍然成立-事件获取器/设置器成为管道推送或拉取,具体取决于您的需求(但通常是推送).

当一组信息发生更改时,通过触发事件也可以完成更复杂的事情.例如,您只想在提供用户名和密码(以及其他信息,例如数据库实例名称,架构等)的情况下连接到数据库.您编写代码的方式-很酷.

Marc
I tried the pipe approach once, and it works fine if you have truly separate processes. As does shared memory, but that was in the days of C++. What I end up doing for what seems to be your need (plugins that don''t actually run in separate processes, but maybe I''m wrong), I just provide a reference to an API that manages containers (bags, collections, whatever you want to call them.) I learned quickly that it''s nice to have different containers, and I also learned that I want to abstract the "variable" (usually it''s a native type, but it could be a complex type as well) so that I can trigger events when the value changes. It also is a good mechanism for doing some client-side validation: the value can''t be null, it has to be within a certain range, etc., all of these constraints and validations can be tied in through the setter event.

So, in short, my solution requires an abstraction of memory management (the container) and an abstraction of a variable (aka memory location) as a full class citizen, the Var.

And quite frankly, if I have to work across processes, the concept still holds - the event getter/setter becomes a pipe push or pull, depending on what your needs are (but usually a push.)

More complicated things can be done as well by triggering an event when a set of information changes. For example, you only want to connect to a database when both username and password have been supplied (and maybe other information, like the database instance name, schema, and so forth.) If you go fully this route, it can literally change the way you code - it''s pretty cool.

Marc


全局变量通常被认为是危险的,因为程序的所有部分都可以随意修改它们,因此很难保证它们的状态在内部是一致的和/或在状态上一致.该程序的其余部分在任何给定时间.

立即想到两个设计注意事项,它们可能有助于您创建可行,可靠且寿命长的体系结构:

1.如果这些全局"值是一次初始化但之后不进行更改,则可以将一个具有只读(仅获取)属性的对象实现为单例,一旦获得其值并通过构造函数参数进行初始化,则实例化.
全局变量的这种使用是安全的,因为一旦初始化,它们就永远不会改变...并且永远也不会改变.后者的保证才是使这些价值观具有全球性的安全保证.它们为程序的其余部分提供了一个(真正的)静态上下文.

2.另一方面,如果期望您正在考虑的变量被程序修改,则它们不构成静态上下文,也不应该是全局的.
在这种情况下,您可能希望按值将一个子系统传递给下一个子系统:这允许每个子系统维护这些变量的值的私有副本,这些变量在模块收到它们时就有效.
如果模块需要更改这些变量的值,则需要考虑当任何一个模块修改这些变量之一的值时程序的其余部分必须如何工作-可能带有某种值更改的通知事件. > 重复前两个子点:
一个.按值传递:模块与程序其余部分中的变量更改保持隔离.
b.传递引用+更改通知:可能会纠结且难以调试;需要很多思考;与全局变量的使用几乎没有什么不同(因为所有子系统都引用了实际值).
Global variables are generally considered dangerous because all parts of the program can modify them at will so it becomes hard to be assured that their state is internally consistent and/or consistent with the state of the rest of the program at any given time.

There are two design considerations that come to mind immediately, that might help you create a workable, reliable and long-lived architecture:

1. If these ''global'' values are initialise-once-but-thereafter-don''t-change, you could make an object, with read-only (get-only) properties, that is implemented as a singleton, instantiated once its values have been obtained and initialised via constructor parameters.
This use of globals is safe because once initialised they never change ... and CAN NEVER change. That latter assurance is what makes it safe to let these values be global. They provide a (truly) static context for the rest of your program.

2. If, on the other hand, the variables you''re considering are expected to be modified by the program, the do NOT constitute a static context and should not be global.
In this case, you may want to pass the from one subsystem to the next by value: this allows each subsystem to maintain a private copy of the values of these variables that were valid at they time the module received them.
If modules need to change the values of these variables you will need to consider how the rest of the program must behave when any one module modifies the value of one of these variables - probably with some kind of value-changed notification event.
Repeating the previous two sub-points:
a. pass-by-value: modules are insulated from changes to the variables in/by the rest of the program
b. pass-by-reference + change notification: can get tangled & hard to debug; needs a lot of thought; is little different from the use of globals (since all subsystems have a reference to the actual value).


这篇关于数据共享,静态变量和管道的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆