.NET Framework 4.5中的System.Net.Http.HttpClient和System.Net.Http.HttpClientHandler实现了IDisposable(通过System.Net.Http.HttpMessageInvoker).
该using
声明文件说:
通常,当您使用IDisposable对象时,您应该在using语句中声明并实例化它.
这个答案使用了这种模式:
var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("foo", "bar"),
new KeyValuePair<string, string>("baz", "bazinga"),
});
cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
var result = client.PostAsync("/test", content).Result;
result.EnsureSuccessStatusCode();
}
Run Code Online (Sandbox Code Playgroud)
但是微软最明显的例子并没有Dispose()
明确地或隐含地调用.例如:
我有一个Parallel.ForEach()异步循环,我下载了一些网页.我的带宽有限,所以我每次只能下载x页,但Parallel.ForEach会执行所需网页的完整列表.
有没有办法在运行Parallel.ForEach时限制线程号或任何其他限制器?
演示代码:
Parallel.ForEach(listOfWebpages, webpage => {
Download(webpage);
});
Run Code Online (Sandbox Code Playgroud)
真正的任务与网页无关,因此创意网络抓取解决方案无济于事.
在metro应用程序中,我需要执行许多WCF调用.有大量的调用,所以我需要在并行循环中进行调用.问题是并行循环在WCF调用完成之前退出.
你会如何重构这个按预期工作?
var ids = new List<string>() { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
var customers = new System.Collections.Concurrent.BlockingCollection<Customer>();
Parallel.ForEach(ids, async i =>
{
ICustomerRepo repo = new CustomerRepo();
var cust = await repo.GetCustomer(i);
customers.Add(cust);
});
foreach ( var customer in customers )
{
Console.WriteLine(customer.ID);
}
Console.ReadKey();
Run Code Online (Sandbox Code Playgroud) 我想并行处理一个集合,但是我在实现它时遇到了麻烦,因此我希望得到一些帮助.
如果我想在并行循环的lambda中调用C#中标记为async的方法,则会出现问题.例如:
var bag = new ConcurrentBag<object>();
Parallel.ForEach(myCollection, async item =>
{
// some pre stuff
var response = await GetData(item);
bag.Add(response);
// some post stuff
}
var count = bag.Count;
Run Code Online (Sandbox Code Playgroud)
计数为0时会出现问题,因为创建的所有线程实际上只是后台线程,并且Parallel.ForEach
调用不等待完成.如果我删除async关键字,该方法如下所示:
var bag = new ConcurrentBag<object>();
Parallel.ForEach(myCollection, item =>
{
// some pre stuff
var responseTask = await GetData(item);
responseTask.Wait();
var response = responseTask.Result;
bag.Add(response);
// some post stuff
}
var count = bag.Count;
Run Code Online (Sandbox Code Playgroud)
它工作,但它完全禁用等待聪明,我必须做一些手动异常处理..(为简洁起见删除).
如何实现一个Parallel.ForEach
在lambda中使用await关键字的循环?可能吗?
Parallel.ForEach方法的原型采用Action<T>
as参数,但我希望它等待我的异步lambda.
我想运行一堆异步任务,并限制在任何给定时间可以完成的任务数量.
假设您有1000个网址,并且您只希望一次打开50个请求; 但只要一个请求完成,您就会打开与列表中下一个URL的连接.这样,一次只打开50个连接,直到URL列表用完为止.
如果可能的话,我也想利用给定数量的线程.
我提出了一种扩展方法,ThrottleTasksAsync
可以实现我想要的功能.那里有更简单的解决方案吗?我认为这是一种常见的情况.
用法:
class Program
{
static void Main(string[] args)
{
Enumerable.Range(1, 10).ThrottleTasksAsync(5, 2, async i => { Console.WriteLine(i); return i; }).Wait();
Console.WriteLine("Press a key to exit...");
Console.ReadKey(true);
}
}
Run Code Online (Sandbox Code Playgroud)
这是代码:
static class IEnumerableExtensions
{
public static async Task<Result_T[]> ThrottleTasksAsync<Enumerable_T, Result_T>(this IEnumerable<Enumerable_T> enumerable, int maxConcurrentTasks, int maxDegreeOfParallelism, Func<Enumerable_T, Task<Result_T>> taskToRun)
{
var blockingQueue = new BlockingCollection<Enumerable_T>(new ConcurrentBag<Enumerable_T>());
var semaphore = new SemaphoreSlim(maxConcurrentTasks);
// Run the throttler on a separate thread.
var t = Task.Run(() => …
Run Code Online (Sandbox Code Playgroud) 我有一些方法Task<T>
可以随意返回await
.我想让这些任务在自定义TaskScheduler
而不是默认的上执行.
var task = GetTaskAsync ();
await task;
Run Code Online (Sandbox Code Playgroud)
我知道我可以创建一个新的TaskFactory (new CustomScheduler ())
并StartNew ()
从中做一个,但是StartNew ()
需要一个动作并创建它Task
,我已经拥有了Task
(在幕后由a返回TaskCompletionSource
)
我怎样才能指定我自己TaskScheduler
的await
?
我有一个1000输入消息的集合来处理.我正在循环输入集合并为每个消息启动新任务以进行处理.
//Assume this messages collection contains 1000 items
var messages = new List<string>();
foreach (var msg in messages)
{
Task.Factory.StartNew(() =>
{
Process(msg);
});
}
Run Code Online (Sandbox Code Playgroud)
我们可以猜测当时同时处理多少个最大消息(假设是普通的四核处理器),还是我们可以限制当时要处理的最大消息数?
如何确保以与Collection相同的顺序/顺序处理此消息?
我正在进行WebCrawler 实现,但在ASP.NET Web API的HttpClient中遇到了奇怪的内存泄漏.
所以减少版本在这里:
我发现了问题,并没有HttpClient泄漏.看我的回答.
我添加了dispose没有效果:
static void Main(string[] args)
{
int waiting = 0;
const int MaxWaiting = 100;
var httpClient = new HttpClient();
foreach (var link in File.ReadAllLines("links.txt"))
{
while (waiting>=MaxWaiting)
{
Thread.Sleep(1000);
Console.WriteLine("Waiting ...");
}
httpClient.GetAsync(link)
.ContinueWith(t =>
{
try
{
var httpResponseMessage = t.Result;
if (httpResponseMessage.IsSuccessStatusCode)
httpResponseMessage.Content.LoadIntoBufferAsync()
.ContinueWith(t2=>
{
if(t2.IsFaulted)
{
httpResponseMessage.Dispose();
Console.ForegroundColor = ConsoleColor.Magenta;
Console.WriteLine(t2.Exception);
}
else
{
httpResponseMessage.Content.
ReadAsStringAsync()
.ContinueWith(t3 =>
{
Interlocked.Decrement(ref waiting);
try
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(httpResponseMessage.RequestMessage.RequestUri); …
Run Code Online (Sandbox Code Playgroud) 根据文件:
"a
SemaphoreSlim
不使用Windows内核信号量".
是否有任何特殊资源SemaphoreSlim
使得Dispose
在SemaphoreSlim
不再使用遗嘱时呼叫很重要?
等待故障任务(具有异常集的任务)时,await
将重新抛出存储的异常.如果存储的异常是a AggregateException
,它将重新抛出第一个并丢弃其余的异常.
我们如何使用await
并同时抛出原件AggregateException
以便我们不会意外丢失错误信息?
注意,当然可以考虑使用hacky解决方案(例如,试一试await
,然后调用Task.Wait
).我真的希望找到一个干净的解决方案.这里最好的做法是什么?
我想过使用自定义awaiter,但内置TaskAwaiter
包含很多魔法,我不知道如何完全重现.它调用TPL类型的内部API.我也不想重现所有这些.
如果你想玩它,这是一个简短的repro:
static void Main()
{
Run().Wait();
}
static async Task Run()
{
Task[] tasks = new[] { CreateTask("ex1"), CreateTask("ex2") };
await Task.WhenAll(tasks);
}
static Task CreateTask(string message)
{
return Task.Factory.StartNew(() => { throw new Exception(message); });
}
Run Code Online (Sandbox Code Playgroud)
只抛出两个例外中的一个Run
.
请注意,Stack Overflow上的其他问题无法解决此特定问题.建议重复时请小心.
c# ×10
async-await ×5
.net ×4
asynchronous ×2
idisposable ×2
semaphore ×2
.net-4.5 ×1
c#-5.0 ×1
dispose ×1
memory-leaks ×1
throttling ×1
tpl-dataflow ×1
using ×1
wcf ×1