所以我正在编写客户端API PCL(.NET 4.5,SL 5,Win8,WP8.1,WP SL 8)库,我决定一次只允许一个HTTP请求。目前我使用TPL来完成它们:
Task.Factory.FromAsync<Stream>(httpReq.BeginGetRequestStream, httpReq.EndGetRequestStream, null).ContinueWith<Task<WebResponse>>((requestStreamTask) =>
{
return Task<WebResponse>.Factory.FromAsync(httpReq.BeginGetResponse, httpReq.EndGetResponse, null);
}).Unwrap().ContinueWith<HttpWebResponse>((getResponseTask) =>
{
return (HttpWebResponse)getResponseTask.Result;
});
所以我想添加锁定以防止一次发出多个请求。我知道我可以在开始之前致电Monitor.Enter
并在最后Monitor.Exit
中致电ContinueWith
。但是基于Migrating lock to TPL,由于可能存在线程问题,我无法使用Monitor
。我没有使用像帖子推荐的那样使用不同的阻塞对象,但据我所知,我的PCL中唯一可用的锁是Monitor。
那我该怎么办?
编辑:在与Yuval Itzchakov交谈后,我意识到我只有Monitor
课程进行同步的原因是因为我的PCL支持Silverlight 5。如果没有别的办法,我会考虑放弃对SL5的支持,但我宁愿不这样做。
EDIT2:在搞砸了我意识到我确实拥有ManualResetEvent
课程后,我可以使用它吗?
答案 0 :(得分:2)
由于您正在编写PCL并包含一些较旧的平台(特别是SL5),因此您的选择有限。 SL5不支持TPL数据流,SemaphoreSlim
也不支持。
但是,HttpClient
is和so are async
/await
。这些允许您的代码远远超过Task.Factory.FromAsync
+ Unwrap
+ ContinueWith
。
对于便携式async
- 就绪同步和/或生产者/消费者队列,我推荐自己的AsyncEx library。在这种情况下,AsyncLock
就足够了;它可以与SemaphoreSlim
:
private readonly HttpClient _client = new HttpClient();
private readonly AsyncLock _mutex = new AsyncLock();
public async Task<string> GetStringAsync(string url)
{
using (await _mutex.LockAsync())
{
return await _client.GetStringAsync(url);
}
}
答案 1 :(得分:1)
首先,在该答案中,我使用SemaphoreSlim
在PCL支持的documentation中说明,因此您可以使用它代替Monitor
。
其次,作为Jon Skeet pointed out,您可以使用TPL数据流ActionBlock
(PCL也支持async-await
:
var block = new ActionBlock<HttpWebRequest>(request =>
{
var result = await request.GetResponseAsync();
// handle result
}
HttpWebRequest newRequest = // ...
block.Post(newRequest);
该块一次处理一个请求,并使用Post
添加新的onces。
答案 2 :(得分:0)
而不是使用相当冗长的FromAsync
模式,您可以使用支持PCL的HttpClient
和SemaphoreSlim
(如Arnon和Jon所提到的):
private SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
private HttpClient _httpClient = new HttpClient();
public async Task SendRequestAsync(HttpWebRequest request)
{
await _semaphoreSlim.WaitAsync();
try
{
return await _httpClient.SendAsync(request);
}
finally
{
_semaphoreSlim.Release();
}
}