c# - 如何在 C# 中处理多个并发交互的实体

标签 c# .net concurrency

我正在开发一个应用程序,该应用程序具有许多可以同时交互的不同实体。我想知道这些实体以线程安全的方式相互交互的最佳方式是什么。

为了用一些简化的代码进行演示,请考虑每个实体都有自己的光纤和一些状态:

class Fiber
{
    private ActionBlock<Action> _workQueue;

    public Fiber()
    {
        _workQueue = new ActionBlock<Action>((a) => a());
    }

    public void Enqueue(Action a)
    {
        _workQueue.Post(a);
    }

    public void Stop()
    {
        _workQueue.Complete();
    }
}

class EntityState
{
    public int x { get; set; }
}

class Entity
{
    private Fiber _fiber = new Fiber();

    public EntityState State { get; set; }

    // ...
}

假设操作被任意排队到实体纤程上。一个这样的 Action 可能是一个实体必须修改另一个实体的状态。我考虑过两种选择以线程安全的方式执行此操作。

选项 1:仅允许通过线程安全包装器进行状态突变,I.E.

class Entity
{
    private Fiber _fiber = new Fiber();

    private ReaderWriterLockSlim _stateLock = new ReaderWriterLockSlim();
    private EntityState _state = new EntityState();

    public T ReadState<T>(Func<EntityState, T> reader)
    {
        T result = default(T);

        _stateLock.EnterReadLock();
        result = reader(_state);
        _stateLock.ExitReadLock();

        return result;
    }

    public void WriteState(Action<EntityState> writer)
    {
        _stateLock.EnterWriteLock();
        writer(_state);
        _stateLock.ExitWriteLock();
    }

    // ...
}

选项 2:仅通过将其调度到拥有实体的纤程上并返回 Future 来允许状态突变,以便突变者可以看到突变何时发生,即

class Future<T>
{
    public T Value { get; set; }
}

class Entity
{
    private Fiber _fiber = new Fiber();

    private EntityState _state = new EntityState();

    public Future<T> AccessState<T>(Func<EntityState, T> accessor)
    {
        Future<T> future = new Future<T>();

        _fiber.Enqueue(() => future.Value = accessor(_state));

        return future;
    }

    // ...
}

我还没有考虑过哪些其他选择?有没有好的方法可以做到这一点?我到底应该这样做吗?

最佳答案

你的所有选择都会给你带来痛苦。

  1. 即使代码在技术上是正确的,您也会在域中遇到逻辑竞争条件。像订单这样的东西可以在付款之前发货。
  2. 这会损害可维护性。线程代码很难调试、测试、阅读。当它与应用程序交错时,情况会变得更加复杂。

正确的方法是将线程代码与应用程序代码完全分离。将任务放入单线程纤程中。任务在所有涉及的实体之间同步执行所有作业。任务完成后,就可以异步执行IO了。 我写过a library对于这种方法。

关于c# - 如何在 C# 中处理多个并发交互的实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17749139/

相关文章:

c# - 将数组值写入 SQL 数据库

c# - Moq 和 NHibernate 如何自动创建派生类型?

jQuery ajax 将 jpg 图像发布到 .net web 服务。图像结果已损坏

objective-c - 如何同时保存 NSDocument?

c# - 与 Process Explorer 的 TID 相对应的 System.Threading.Thread 的属性/属性/字段是什么?

c# - 如何在asp.net中获取应用程序路径?

c# - 在 C# 中获取 NamedRange 控件的句柄

java - BufferedImage 的后台创建以及与信号量的同步

java - JVM线程调度算法是什么?

c# - 从另一个线程更新 Blazor 中的项目列表