相关疑难解决方法(0)

强制执行一次异步方法

假设我有一个需要使用InitializeAsync()方法执行异步初始化的类.我想确保初始化只执行一次.如果另一个线程在初始化正在进行时调用此方法,它将"等待"直到第一个调用返回.

我正在考虑以下的实现(使用SemaphoreSlim).有更好/更简单的方法吗?

public class MyService : IMyService
{
    private readonly SemaphoreSlim mSemaphore = new SemaphoreSlim(1, 1);
    private bool mIsInitialized;

    public async Task InitializeAsync()
    {
        if (!mIsInitialized)
        {
            await mSemaphore.WaitAsync();

            if (!mIsInitialized)
            {
                await DoStuffOnlyOnceAsync();
                mIsInitialized = true;
            }

            mSemaphore.Release();
        }
    }

    private Task DoStuffOnlyOnceAsync()
    {
        return Task.Run(() =>
        {
            Thread.Sleep(10000);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

编辑:

由于我正在使用DI并且将注入此服务,因此将其作为"懒惰"资源使用或使用异步工厂对我来说不起作用(尽管在其他用例中它可能很好).因此,异步初始化应该封装在类中,并对IMyService消费者透明.

将初始化代码包装在"虚拟" AsyncLazy<>对象中的想法将完成这项工作,尽管对我来说感觉有点不自然.

.net c# asynchronous task-parallel-library async-await

13
推荐指数
3
解决办法
2301
查看次数

如何在.NET ConcurrentDictionary中实现remove_if功能

我有一个场景,我必须保持引用计数对象的给定键ConcurrentDictionary,如果引用计数达到0,我想删除键.这必须是线程安全的,因此我打算使用ConcurrentDictionary.

示例程序如下.在并发字典中,我有键和值,值是KeyValuePair,它保存我的自定义对象和引用计数.

ConcurrentDictionary<string, KeyValuePair<object, int>> ccd = 
    new ConcurrentDictionary<string, KeyValuePair<object, int>>();

// following code adds the key, if not exists with reference 
// count   for  my custom object to 1
// if the key already exists it increments the reference count

var addOrUpdateValue = ccd.AddOrUpdate("mykey",
    new KeyValuePair<object, int>(new object(), 1),
    (k, pair) => new KeyValuePair<object, int>(pair.Key, pair.Value + 1));
Run Code Online (Sandbox Code Playgroud)

现在我想要一种方法来在引用计数达到0时删除密钥.我在想,删除带有ConcurrentDictionary键和谓词的方法,如果谓词返回'true'则删除密钥.例.

ConcurrentDictionary.remove(TKey, Predicate<TValue> ). 
Run Code Online (Sandbox Code Playgroud)

没有这样的方法ConcurrentDictionary,问题是如何以线程安全的方式做同样的事情?

.net c# multithreading task-parallel-library concurrentdictionary

11
推荐指数
2
解决办法
667
查看次数

在 MemoryCache 调用上停止重入

应用程序需要加载数据并缓存一段时间。我希望如果应用程序的多个部分想要同时访问同一个缓存键,缓存应该足够智能,只加载一次数据并将该调用的结果返回给所有调用者。然而,MemoryCache并不是这样做的。如果您并行访问缓存(这通常发生在应用程序中),它会为每次尝试获取缓存值创建一个任务。我认为这段代码会达到预期的结果,但事实并非如此。我希望缓存只运行一项GetDataAsync任务,等待它完成,然后使用结果来获取其他调用的值。

using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ConsoleApp4
{
    class Program
    {
        private const string Key = "1";
        private static int number = 0;

        static async Task Main(string[] args)
        {
            var memoryCache = new MemoryCache(new MemoryCacheOptions { });

            var tasks = new List<Task>();
            tasks.Add(memoryCache.GetOrCreateAsync(Key, (cacheEntry) => GetDataAsync()));
            tasks.Add(memoryCache.GetOrCreateAsync(Key, (cacheEntry) => GetDataAsync()));
            tasks.Add(memoryCache.GetOrCreateAsync(Key, (cacheEntry) => GetDataAsync()));

            await Task.WhenAll(tasks);

            Console.WriteLine($"The cached value was: {memoryCache.Get(Key)}");
        }

        public static async Task<int> GetDataAsync()
        {
            //Simulate getting a large …
Run Code Online (Sandbox Code Playgroud)

.net c# concurrency memorycache concurrentdictionary

6
推荐指数
1
解决办法
431
查看次数

这个 ConcurrentDictionary + Lazy&lt;Task&lt;T&gt;&gt; 代码是如何工作的?

各种 帖子/答案表示,如果键尚不存在,则ConcurrentDictionary GetOrAdd当使用委托计算要插入字典中的值时,.NET/.NET Core 的方法不是线程安全的。Func

我相信,当使用 aConcurrentDictionary的方法的工厂方法时GetOrAdd,如果“同时”发生多个请求,则可以“同时/快速连续地”多次调用它。这可能会造成浪费,尤其是当呼叫“昂贵”时。(@panagiotis-kanavos 比我解释得更好)。有了这个假设,我正在努力理解我制作的一些示例代码似乎是如何工作的。

我已经在 .NET Fiddle 上创建了一个工作示例,但我一直试图理解它是如何工作的。

普通的推荐我读过的建议/想法是Lazy<Task<T>>ConcurrentDictionary. 这个想法是阻止Lazy其他调用执行底层方法。

完成繁重工作的代码的主要部分是这样的:

    public static async Task<DateTime> GetDateFromCache()
    {
        var result = await _cache.GetOrAdd("someDateTime", new Lazy<Task<DateTime>>(async () => 
        {
            // NOTE: i've made this method take 2 seconds to run, each time it's called.
            var someData = await GetDataFromSomeExternalDependency();
            
            return DateTime.UtcNow;
            
        })).Value;
        
        return result;
    }
Run Code Online (Sandbox Code Playgroud)

我是这样读的:

  • 检查 …

.net c# asynchronous concurrentdictionary

5
推荐指数
1
解决办法
896
查看次数

信号量的多线程问题

我需要一段代码,根据参数键只允许同时由 1 个线程执行:

    private static readonly ConcurrentDictionary<string, SemaphoreSlim> Semaphores = new();

    private async Task<TModel> GetValueWithBlockAsync<TModel>(string valueKey, Func<Task<TModel>> valueAction)
    {
        var semaphore = Semaphores.GetOrAdd(valueKey, s => new SemaphoreSlim(1, 1));

        try
        {
            await semaphore.WaitAsync();

            return await valueAction();
        }
        finally
        {
            semaphore.Release(); // Exception here - System.ObjectDisposedException
            if (semaphore.CurrentCount > 0 && Semaphores.TryRemove(valueKey, out semaphore))
            {
                semaphore?.Dispose();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

我时不时地收到错误:

The semaphore has been disposed. : System.ObjectDisposedException: The semaphore has been disposed.
   at System.Threading.SemaphoreSlim.CheckDispose()
   at System.Threading.SemaphoreSlim.Release(Int32 releaseCount)
   at Project.GetValueWithBlockAsync[TModel](String valueKey, Func`1 valueAction) …
Run Code Online (Sandbox Code Playgroud)

.net c# multithreading semaphore

2
推荐指数
1
解决办法
1853
查看次数