gpt4 book ai didi

c# - 如何最好地防止在完成之前再次运行异步方法?

转载 作者:行者123 更新时间:2023-11-30 16:44:11 24 4
gpt4 key购买 nike

我有这种模式可以防止在之前有机会完成之前调用异步方法。

我的解决方案涉及需要一个标志,然后需要锁定标志,感觉非常冗长。有没有更自然的方法来实现这一点?

public class MyClass
{
private object SyncIsFooRunning = new object();
private bool IsFooRunning { get; set;}

public async Task FooAsync()
{
try
{
lock(SyncIsFooRunning)
{
if(IsFooRunning)
return;

IsFooRunning = true;
}

// Use a semaphore to enforce maximum number of Tasks which are able to run concurrently.
var semaphoreSlim = new SemaphoreSlim(5);
var trackedTasks = new List<Task>();

for(int i = 0; i < 100; i++)
{
await semaphoreSlim.WaitAsync();

trackedTasks.Add(Task.Run(() =>
{
// DoTask();
semaphoreSlim.Release();
}));
}

// Using await makes try/catch/finally possible.
await Task.WhenAll(trackedTasks);
}
finally
{
lock(SyncIsFooRunning)
{
IsFooRunning = false;
}
}
}
}

最佳答案

如评论中所述,您可以使用 Interlocked.CompareExchange()如果您愿意:

public class MyClass
{
private int _flag;

public async Task FooAsync()
{
try
{
if (Interlocked.CompareExchange(ref _flag, 1, 0) == 1)
{
return;
}

// do stuff
}
finally
{
Interlocked.Exchange(ref _flag, 0);
}
}
}

也就是说,我认为这是矫枉过正。使用 lock 没问题在这种情况下,特别是如果您不希望在方法上有很多争用。我认为更好的方法是包装方法,以便调用者始终可以 await在结果上,是否启动了一个新的异步操作:

public class MyClass
{
private readonly object _lock = new object();
private Task _task;

public Task FooAsync()
{
lock (_lock)
{
return _task != null ? _task : (_task = FooAsyncImpl());
}
}

public async Task FooAsyncImpl()
{
try
{
// do async stuff
}
finally
{
lock (_lock) _task = null;
}
}
}

最后,在评论中,你这样说:

Seems a bit odd that all the return types are still valid for Task?

我不清楚你的意思。在您的方法中,唯一有效的返回类型是 voidTask .如果你的return语句返回实际值,您必须使用 Task<T>其中 T是返回语句返回的类型。

关于c# - 如何最好地防止在完成之前再次运行异步方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43859525/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com