Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在dotnet核心后台服务中处理实时系统中共享状态的最佳方法_C#_Multithreading_.net Core_Backgroundworker - Fatal编程技术网

C# 在dotnet核心后台服务中处理实时系统中共享状态的最佳方法

C# 在dotnet核心后台服务中处理实时系统中共享状态的最佳方法,c#,multithreading,.net-core,backgroundworker,C#,Multithreading,.net Core,Backgroundworker,我在dotnet core 3.1中有一个后台服务IHostedService,它使用套接字(自制)接收来自100多个客户端(工厂中的机器)的请求。我的问题是,在一个可以访问对象(共享状态)的类上,对同一方法的多个调用可以在不同的线程上进行。这在代码库中很常见。请求也必须按正确的顺序处理 这不在数据库中的原因是由于性能原因(实时系统)。我知道我可以使用锁,但我不想让锁遍布整个代码库 处理这种情况的标准方法是什么。你使用内存数据库吗?内存缓存?还是我必须到处加锁 public class Mach

我在dotnet core 3.1中有一个后台服务
IHostedService
,它使用套接字(自制)接收来自100多个客户端(工厂中的机器)的请求。我的问题是,在一个可以访问对象(共享状态)的类上,对同一方法的多个调用可以在不同的线程上进行。这在代码库中很常见。请求也必须按正确的顺序处理

这不在数据库中的原因是由于性能原因(实时系统)。我知道我可以使用锁,但我不想让锁遍布整个代码库

处理这种情况的标准方法是什么。你使用内存数据库吗?内存缓存?还是我必须到处加锁

public class Machine
{
    
    public MachineState {get; set;}

    // Gets called by multiple threads from multiple clients 
    public bool CheckMachineStatus()
    {
        return MachineState.IsRunning;
    }

    // Gets called by multiple threads from multiple clients 
    public void SetMachineStatus()
    {
        MachineState = Stopped;
    }
}
更新

这里有一个例子。我有一个控制台应用程序,通过插座与机器对话,用于称量产品。当console应用程序初始化时,它会将数据加载到内存中(有关称重产品的信息)。所有这些都在主线程上完成,以保持数据完整性

当来自线程1上的称重器的调用传入时,它将切换到主线程以访问产品信息,并完成任何其他工作,如为系统的其他部分引发事件

目前,从线程1,2,…N到主线程的切换是由一个自制的解决方案完成的,这样做是为了避免在整个代码库中都有锁定代码。这是在.NET1.1中编写的,并且是在迁移到DotnetCore3.1之后编写的。我认为可能有一个框架、库、工具、技术等可以为我们解决这个问题,或者只是一个更好的方法


这是一个我仍在学习的现有系统。希望这是有意义的。

使用内存中的数据库是一种选择,只要您愿意将所有导致并发的情况委托给数据库,并且不使用代码。例如,如果必须根据某些条件更新数据库中的值,则该条件应由数据库检查,而不是由您自己的代码检查

到处添加锁也是一种选择,这几乎肯定会很快导致无法维护的代码。代码可能会在一开始就被隐藏的bug所困扰,这些bug会随着时间的推移一个一个地被发现,通常是在最不幸的情况下

你必须意识到你正在处理一个难题,没有神奇的解决方案。在多线程应用程序中管理共享状态一直是一个痛苦的根源

我的建议是将所有这些复杂性封装在线程安全类中,应用程序的其余部分可以安全地调用这些类。如何使这些类线程安全取决于具体情况

  • 使用锁是最灵活的选择,但并不总是最有效的,因为它有可能产生争用

  • 例如,使用线程安全集合的灵活性较低,因为它们提供的线程安全保证仅限于其内部状态的完整性。例如,如果您必须根据从另一个集合获得的条件更新一个集合,则不能仅通过使用线程安全集合使整个操作成为原子操作。另一方面,这些集合提供了比简单锁更好的性能

  • 例如,使用是另一个有趣的选择。它们在内存和CPU方面的效率都不如并发集合(在许多情况下,添加/删除是O(Log n)而不是O(1)),并且没有比它们更灵活,但它们在提供活动处理数据的快照方面特别高效。要以原子方式更新不可变集合,有一种简便的方法可用。它使用同一集合的更新版本更新不可变集合的引用,而不使用锁。在与其他线程争用的情况下,它可以多次调用提供的转换,直到赢得竞争


  • 您正在保存什么类型的数据?是关系型的吗?你能把它放在键/值存储中吗?如果提供更多的上下文,您会得到更好的响应。性能和原子一致性通常是两者之间的权衡。如果不想使用锁,可以查看
    System.Threading.Interlocked
    类,了解一些可以原子化完成的操作。如果您所做的只是从多个线程读取/更新布尔变量,那么Interlocked类将允许您这样做,而无需锁定。如果您的用例比这更复杂,那么您需要描述它,否则我们将不会太复杂help@insane_developer数据可以是任何东西,一个对象,对象列表,许多变量。我知道我可以使用EF core内存提供程序、Ravendb或Litedb等。由于我是这个领域的新手(来自网络背景),我认为会有一个标准的方法来处理这个场景。我理解这是一个一般性的问题,并将尝试更新我的示例。谢谢。@Andrewilliamson是的,我们有处理原子一致性的代码,就像你提到的Lock、Interlocked和ManualResetEvent。我想看看是否有更好的办法。谢谢。我可能误解了您的问题,但如果您必须按时间顺序处理多线程请求,“多生产者,单消费者”模式不会大大简化事情吗?让套接字处理程序在单个线程安全集合的末尾转储“命令”,然后退出。另一个线程充当处理器,按顺序从集合的头部获取项目,并按接收顺序一次执行一个项目。谢谢您的回答。是的,我想将所有并发情况卸载到数据库中。我认为在这个场景中可能会使用一个通用的框架/工具或数据库。有点像Redis,Dotnet Core M