Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.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# 调用从异步方法锁定的方法。这样合适吗?_C#_Async Await_Thread Synchronization - Fatal编程技术网

C# 调用从异步方法锁定的方法。这样合适吗?

C# 调用从异步方法锁定的方法。这样合适吗?,c#,async-await,thread-synchronization,C#,Async Await,Thread Synchronization,我正在创建一个异步读取资源的东西,但它应该只每隔一段时间读取一次,其他时间返回一个缓存结果。在WebAPI ASP.NET Core 2.1应用程序中,此方法每分钟被调用上千次 我想使用排序锁同步缓存数据,而不需要semaphoreslim对象的开销,因此我想知道这是否合适: private const int LastReadTTL = 5000; private static int _lastTickCountRead; private static Models.

我正在创建一个异步读取资源的东西,但它应该只每隔一段时间读取一次,其他时间返回一个缓存结果。在WebAPI ASP.NET Core 2.1应用程序中,此方法每分钟被调用上千次

我想使用排序锁同步缓存数据,而不需要semaphoreslim对象的开销,因此我想知道这是否合适:

    private const int LastReadTTL = 5000;
    private static int _lastTickCountRead;
    private static Models.MyModel _lastRead;
    private static readonly object _lock = new object();

    private static bool ShouldRead()
    {
        lock(_lock)
        {
            var currentTickCount = Environment.TickCount;
            if ((_lastRead == null) || (currentTickCount > (_lastTickCountRead + LastReadTTL)) || (currentTickCount < _lastTickCountRead))
            {
                _lastTickCountRead = currentTickCount;
                return true;
            }
        }
        return false;
    }

    public async Task<Models.MyModel> ReadSomethingAsync()
    {
        if (ShouldRead())
        {
            _lastRead = await SomethingToReadAsync.ConfigureAwait(false);
        }
        return _lastRead;
    }
private const int LastReadTTL=5000;
私有静态int_lastTickCountRead;
私有静态模型.MyModel\u lastRead;
私有静态只读对象_lock=new object();
私有静态bool ShouldRead()
{
锁
{
var currentTickCount=Environment.TickCount;
如果((_lastRead==null)|(currentTickCount>(_lastTickCountRead+LastReadTTL))|(currentTickCount<_lastTickCountRead))
{
_lastTickCountRead=当前TickCount;
返回true;
}
}
返回false;
}
公共异步任务ReadSomethingAsync()
{
if(ShouldRead())
{
_lastRead=await SomethingToReadAsync.ConfigureAwait(false);
}
返回上次读取;
}
如果这不合适,为什么?在这种情况下,使用信号量lim更合适吗


谢谢

这个问题应该放在codereview.stackexchange.com上,而不是stackoverflow上。如果问题没有被移动,我的答案是否定的,一般来说,锁定异步方法不是一个好模式

原因是异步方法被设计为在无法进行时(通常等待IO完成)产生控制,因此线程可以切换到准备继续的其他任务。通过阻塞线程,它强制操作系统执行到另一个线程的上下文切换,稍后当锁为阻塞线程准备好时,再次执行另一个上下文切换。Async是专门为减少上下文切换的性能损失而设计的,因此阻止一个异步方法会消除该功能的好处

我建议使用任何返回您可以等待的任务的同步对象,无论是semaphoreslim、来自AsyncEx nuget包的东西,还是其他任何东西。希望所有创建这些的人都比你我更了解.NET中的异步,所以应该比我们自己实现的任何东西都更好。他们很有可能会使用阻塞同步对象,但这样做只是为了避免竞争条件,并在异步对象未成功获得锁时快速退回到异步等待,因此在提供并发系统所需的同步保证的同时,提供异步的优势


话虽如此,如果您的用例只是周期性地更新一个值,那么您应该看看哪种方法为您提供了更新值或对象实例的无锁方式。

每次我问一个没有发布代码的问题时,我都会因为没有发布代码而被骂。我认为SO上的每个问题都是一个代码审查,取决于您希望的粒度。无论如何,谢谢你的回答。我将转到
信号量lim
来完成我所需要的。我的理解是,SO应该是关于非常具体的问题,比如“我试图做X,我期望结果Y,但我看到结果Z。”我认为这个问题更广泛,答案可能更主观,因此,可能更适合代码审查或软件工程网站。如果您发布的代码与实际代码有点类似,我的第一个建议是,锁中的大部分代码都可以移出,您只需要在ReadSomething方法更新值时锁定它。这样,当缓存的值未过期时,就不会使用锁。这意味着您需要执行两次检查,一次在锁之前,一次在锁内部,以避免多次执行该工作,但如果锁以前经常被击中,性能应该会大大提高。此外,由于这是关于缓存数据的,它告诉我,应用程序使用稍微旧的数据可能并不重要。因此,与其在第一个线程刷新数据时锁定其他线程,不如继续使用现有的缓存数据。使用锁仅可避免多个线程试图同时更新该值,尽管您也可以使用Interlocked.Exchange以无锁的方式执行此操作。最后,您发布的代码会执行某种“延迟加载”,因此如果您的网站停止获取流量(至少是访问此代码路径的流量),您将停止更新该值。但是,如果您通常不会获得这段不活动时间,您可以创建一个新线程,该线程将一直休眠到下一个缓存过期时间,然后刷新数据,并且您的计算线程只读取数据,而不检查数据是否已过期,这样您的热代码路径就没有同步代码使其减速。