LCC*_*LCC 2 c# asynchronous httpclient async-await windows-runtime
在我的win8(winrt,c#)应用程序中,我需要调用一个具有非常特定限制的Web API:每2秒不再调用一次Web服务.
我试图强制执行此限制,如下所示:
class Client
{
const int Delay = 2000;
HttpClient m_client = new HttpClient();
int m_ticks = 0;
public async Task<string> Get(string url)
{
// Multiple threads could be calling, I need to protect access to m_ticks:
string result = null;
lock (this)
{
int ticks = Environment.TickCount - m_ticks;
if (ticks < Delay)
await Task.Delay(Delay - ticks);
result = await m_client.GetStringAsync(url);
m_ticks = Environment.TickCount;
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
这让我陷入了困境:
我怎么会这样写这样的东西?
该SemaphoreSlim类型在.NET 4.5中扩展为包含await兼容的WaitAsync方法.它没有IDisposable基础Release,但建立一个并不难:
sealed class SemaphoreSlimReleaser : IDisposable
{
SemaphoreSlim mutex;
public SemaphoreSlimReleaser(SemaphoreSlim mutex)
{
this.mutex = mutex;
}
void Dispose()
{
if (mutex == null)
return;
mutex.Release();
mutex = null;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用与你已经拥有的代码非常相似的代码:
class Client
{
const int Delay = 2000;
HttpClient m_client = new HttpClient();
int m_ticks = 0;
SemaphoreSlim mutex = new SemaphoreSlim(1);
public async Task<string> Get(string url)
{
// Multiple threads could be calling, I need to protect access to m_ticks:
string result = null;
await mutex.WaitAsync();
using (new SemaphoreSlimReleaser(mutex))
{
int ticks = Environment.TickCount - m_ticks;
if (ticks < Delay)
await Task.Delay(Delay - ticks);
result = await m_client.GetStringAsync(url);
m_ticks = Environment.TickCount;
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
PS如果您有兴趣,我的AsyncEx库有一整套async兼容的同步原语,灵感来自Stephen Toub的博客系列.