C# PCL中的TPL与监视器

C# PCL中的TPL与监视器,c#,.net,task-parallel-library,blocking,portable-class-library,C#,.net,Task Parallel Library,Blocking,Portable Class Library,所以我正在编写一个客户端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>>((requestStrea

所以我正在编写一个客户端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;
    });
Task.Factory.fromsync(httpReq.BeginGetRequestStream,httpReq.EndGetRequestStream,null)。ContinueWith((requestStreamTask)=>
{
返回Task.Factory.fromsync(httpReq.BeginGetResponse,httpReq.EndGetResponse,null);
}).Unwrap().ContinueWith((getResponseTask)=>
{
返回(HttpWebResponse)getResponseTask.Result;
});
因此,我想添加锁定,以防止一次发出多个请求。我知道我可以简单地调用
监视器。在开始之前输入
,然后调用
监视器。在最后一次
继续时退出
。但是基于,我不能像那样使用
监视器
,因为可能存在线程问题。我没有问题使用一个不同的阻塞对象,就像帖子推荐的那样,但就我在PCL中所知,我唯一可用的锁是监视器

那我该怎么办

编辑:在下面与Yuval Itzhakov交谈之后,我意识到我只有
监视器
类用于同步的原因是因为我的PCL中支持Silverlight 5。如果没有其他办法,我会考虑放弃对SL5的支持,但我不想


EDIT2:在闲逛之后,我意识到我确实有
ManualResetEvent
类,我可以使用它吗?

首先,在这个答案中,我使用了
信号量lim
,它在PCL中受支持,所以你可以使用它来代替
监视器

其次,您可以使用TPL数据流的
ActionBlock
(PCL中也支持
async wait
):

var block = new ActionBlock<HttpWebRequest>(request => 
{
    var result = await request.GetResponseAsync();
    // handle result
}

HttpWebRequest newRequest = // ...
block.Post(newRequest);
var block=newactionblock(请求=>
{
var result=wait request.GetResponseAsync();
//处理结果
}
HttpWebRequest newRequest=/。。。
block.Post(新请求);

块一次处理一个请求,您可以使用
Post

添加新的请求,而不是使用非常详细的
fromsync
模式,您可以使用和
信号量lim
(正如Arnon和Jon提到的)来支持PCL:

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();
      }
}

由于您正在编写PCL,并且包含一些较旧的平台(特别是SL5),因此您的选择有点有限。SL5上不支持TPL数据流,
SemaphoreSlim

但是,和。这些允许您的代码比
任务.Factory.fromsync
+
展开
+
继续
更干净

对于可移植的
async
-就绪同步和/或生产者/消费者队列,我建议使用我自己的队列。在这种情况下,
AsyncLock
就足够了;它可以以类似于
信号量lim
的方式使用:

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);
    }
}
private readonly HttpClient _client=new HttpClient();
私有只读异步锁_mutex=new AsyncLock();
公共异步任务GetStringAsync(字符串url)
{
使用(wait_mutex.lockaync())
{
返回wait_client.GetStringAsync(url);
}
}

听起来您可能想使用生产者/消费者模式,其中一个线程负责所有HTTP请求-您创建一个队列,然后线程处理该队列。您可以查看
BlockingCollection
,甚至可能查看TPL数据流。我希望使用
BlockingCollection
,但我不支持它n我正在使用的PCL配置。与TPL数据流相同。我希望使用
SemaphoreSlim
和TPL数据流,但在我的PCL配置中两者都不受支持。虽然我正在使用的PCL配置中不支持
SemaphoreSlim
,但使用HTTP客户端是一个有趣的想法。更有趣的是,它需要uires其他软件包为我的配置提供了Async/Await,这将在多个级别上简化我的代码基础。所以我必须看看这个。你说的“PCL配置im使用”是什么意思?我将PCL设置为支持.NET 4.5、Silverlight 5、Windows 8、Windows Phone 8.1和Windows Phone Silverlight 8。通过将其设置为我拥有的所有API,我知道了。我认为限制您的是SL5。我知道所有其他平台都受支持。刚刚从支持中删除Silverlight 5,并访问了
信号量lim
。因此,如果没有其他方法,我可能不得不放弃Silverlight支持。我目前正在考虑在库中使用Async/Wait和
HttpClient
。我不想这么做的主要原因是这样做需要重写大量代码,而这不是我不想就要做的事情t、 你的异步锁看起来正是我想要的,hmmmmmmmmm@shmuelie:您可以使用
ContinueWith
;只是
await
容易得多。您的意思是我可以将您的
AsyncLock
ContinueWith
一起使用,那么您可能是赢家!我建议您使用
await
编写任何新代码。我只是说ing您可以添加
Microsoft.Bcl.Async
并使用
wait
来获取新代码,而无需重写“大量代码”。我个人不喜欢混合使用各种方法来做事情,但短期内我可能会这么做