相关疑难解决方法(0)

如何限制并发异步I/O操作的数量?

// let's say there is a list of 1000+ URLs
string[] urls = { "http://google.com", "http://yahoo.com", ... };

// now let's send HTTP requests to each of these URLs in parallel
urls.AsParallel().ForAll(async (url) => {
    var client = new HttpClient();
    var html = await client.GetStringAsync(url);
});
Run Code Online (Sandbox Code Playgroud)

这是问题所在,它会同时启动1000多个Web请求.有没有一种简单的方法来限制这些异步http请求的并发数量?这样在任何给定时间都不会下载超过20个网页.如何以最有效的方式做到这一点?

c# asynchronous task-parallel-library async-await async-ctp

103
推荐指数
5
解决办法
4万
查看次数

我如何选择Semaphore和SemaphoreSlim?

他们的公共界面看似相似.该文档指出SemaphoreSlim是一种轻量级替代方案,不使用Windows内核信号量. 该资源表明SemaphoreSlim速度更快.SemaphoreSlim在什么情况下对信号量更有意义,反之亦然?

c# multithreading semaphore

98
推荐指数
4
解决办法
2万
查看次数

使用Task作为返回类型从非异步方法返回什么?

假设我有一个非异步但返回的方法Task(因为定义来自同样用于异步实现的接口)

public Task DoWorkAsync(Guid id)
{
     // do the work

     return ...;
}
Run Code Online (Sandbox Code Playgroud)

什么是最好的回归对象?我目前的选择:

return Task.Yield();
return Task.FromResult<object>(null);

// any of the other but cached in a static field and reused.
Run Code Online (Sandbox Code Playgroud)

c# async-await

16
推荐指数
2
解决办法
6921
查看次数

是否有PLINQ的异步版本?

我想在一定程度的并行处理并行处理项目的同时对数据流执行查询.通常情况下,我会使用PLINQ,但我的工作项不是CPU绑定的,而是IO绑定的.我想使用异步IO.PLINQ不支持异步工作.

运行PLINQ样式查询的最聪明方法是什么,但使用异步工作项?


以下是该问题的更详细说明:

我的目标是以下面的查询逻辑描述的方式处理可能无限的"项目"流:

var items = new int[10]; //simulate data

var results =
 from x in items.AsParallel().WithDegreeOfParallelism(100)
 where Predicate(x)
 select ComputeSomeValue(x);

foreach (var result in results)
 PerformSomeAction(result);
Run Code Online (Sandbox Code Playgroud)

此查询只是真实查询的草图.现在我希望每个占位符函数都是异步的(返回a Task和内部基于异步IO).

请注意,可能存在的内容远远多于可以存储在内存中的项目.我还必须控制并行度以最大化底层网络和磁盘硬件.

这个问题不是关于多核的.它完全适用于只有一个CPU内核的机器,因为IO仍然可以从并行性中受益.想想慢速的Web服务调用等.

.net asynchronous plinq task-parallel-library

14
推荐指数
2
解决办法
1027
查看次数

使用自己的ThreadPool继续任务

是否可以强制继续使用async-await语句在自定义ThreadPool的线程上运行?

上下文:我正在运行一个ASP应用程序并在后台做了相当多的工作.我正在通过自编写的ThreadPool完成所有工作,但如果我使用async-await模式,则延续总是在名为"Worker Thread"的线程上运行.我很确定这是来自默认ThreadPool的线程,它也用于处理HTTP请求.由于默认ThreadPool的所有线程都忙着继续我的后台工作,这导致这些请求的饥饿.

.net c# task-parallel-library async-await

7
推荐指数
2
解决办法
828
查看次数

带有 Select 的 Task.WhenAll 是一把枪——但为什么呢?

考虑:您有一组用户 ID,并希望从 API 加载由其 ID 表示的每个用户的详细信息。您希望将所有这些用户打包到某种集合中并将其发送回调用代码。并且您想使用 LINQ。

像这样的东西:

var userTasks = userIds.Select(userId => GetUserDetailsAsync(userId));
var users = await Task.WhenAll(tasks); // users is User[]
Run Code Online (Sandbox Code Playgroud)

当我的用户相对较少时,这对我的应用程序来说很好。但是,它出现了无法扩展的情况。当它到达成千上万的用户时,这导致同时触发了数千个 HTTP 请求,并且开始发生不好的事情。我们不仅意识到我们正在对我们正在使用的 API 发起拒绝服务攻击,而且我们还通过线程饥饿使我们自己的应用程序崩溃。

不是骄傲的一天。

一旦我们意识到我们的困境的原因是Task.WhenAll/Select组合,我们就能够摆脱这种模式。但我的问题是:

这里出了什么问题?

当我阅读有关该主题的内容时,Mark Heath 的异步反模式列表中的#6 似乎很好地描述了这种情况:“过度并行化”:

现在,这确实“有效”,但是如果有 10,000 个订单呢?我们已经用数千个任务淹没了线程池,可能会阻止其他有用的工作完成。如果 ProcessOrderAsync 对另一个服务(如数据库或微服务)进行下游调用,我​​们可能会因调用量过高而使该服务过载。

这真的是原因吗?我问的越多,我对async/ 的理解await就越不清晰。从许多文章中可以清楚地看出“线程不是任务”。这很酷,但我的代码似乎耗尽了 ASP.NET Core 可以处理的线程数。

那么是这样吗?我的Task.WhenAllSelect组合是否耗尽了线程池或类似的东西?或者还有其他我不知道的解释吗?

更新:

我把这个问题变成了一篇博客文章,里面有更多细节/华夫饼。你可以在这里找到它:https : //blog.johnnyreilly.com/2020/06/taskwhenall-select-is-footgun.html

linq task threadpool async-await

7
推荐指数
2
解决办法
581
查看次数

动态更改 HttpClient 中的代理,无需硬 CPU 使用

我需要创建一个发出请求(发布、获取等)的多线程应用程序,为此我选择了Httpclient.

默认情况下它不支持 Socks 代理。所以我发现Sockshandlerhttps://github.com/extremecodetv/SocksSharp)可以用来代替基本的 HttpClientHandler。它允许我使用袜子。

但我有一个问题。我的所有请求都应该通过我从互联网解析的不同代理发送。但 httpclient 处理程序不支持动态更改代理。如果我没有有效的代理,我需要重新创建一个httclient,这没问题,但是如果我有200个线程,则需要大量的cpu。那么这种情况我该怎么办呢?

第二个问题。我发现这篇文章(https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/HttpClient )讨论了作为单个实例使用以获得更好的性能,但在多线程程序中这是不可能的。在这种情况下哪种方式更好?

谢谢帮助

c# multithreading httpclient socks proxies

6
推荐指数
1
解决办法
5849
查看次数

HttpClient 中有多少个连接

背景

我必须从互联网上下载大约 16k 个文档和相同数量的 html 页面。这个数字在未来还会增加。目前我只是Parallel.ForEach用来并行下载和处理数据。然而,这似乎并没有充分利用我的资源,所以我计划async/await发挥作用,尽可能多地异步运行下载,但我可能不得不限制它。

实际问题

单个可以有多少个打开的连接HttpClient?在创建如此大量的连接时,我还必须记住哪些其他因素?我知道我应该重用它HttpClient,我也阅读了这个答案,但我怀疑我是否真的可以同时打开数十亿个连接。

c# dotnet-httpclient

6
推荐指数
1
解决办法
5965
查看次数

.NET Throttle算法

我想在.net(C#或VB)中实现一个好的油门算法,但我无法弄清楚我怎么能这样做.

案例是我的asp.net网站应该将请求发布到另一个网站以获取结果.最多应发送每分钟300个请求.

如果请求超过300限制,则另一方Api不返回任何内容(这是我不想用作检查代码的内容).

PS我见过其他语言的解决方案而不是.net但我是新手,请善待并保持你的答案就像123一样简单.

谢谢

.net c# vb.net throttling

5
推荐指数
1
解决办法
4763
查看次数

异步/等待或任务。在控制台应用程序/ Windows服务中运行

我一直在研究(包括查看此主题的所有其他SO帖子)实现(最可能的)Windows Service worker的最佳方法,该服务将从数据库中提取工作项并在“解雇后-forget'方式在后台进行(工作项管理全部以异步方法处理)。工作项将是Web服务调用和数据库查询。这些工作项的生产者将受到一些限制,以确保某种可衡量的方法来安排工作。下面的示例非常基础,仅用来突出while循环和for循环的逻辑。哪种方法比较理想或没关系?有没有更合适/更有效的方法来实现这一目标?

异步/等待...

    private static int counter = 1;

    static void Main(string[] args)
    {
        Console.Title = "Async";

        Task.Run(() => AsyncMain());

        Console.ReadLine();            
    }

    private static async void AsyncMain()
    {
        while (true)
        {
            // Imagine calling a database to get some work items to do, in this case 5 dummy items
            for (int i = 0; i < 5; i++)
            {
                var x = DoSomethingAsync(counter.ToString());

                counter++;
                Thread.Sleep(50);
            }

            Thread.Sleep(1000);
        }
    }

    private static async Task<string> DoSomethingAsync(string jobNumber)
    {
        try
        {
            // …
Run Code Online (Sandbox Code Playgroud)

.net c# asynchronous task-parallel-library async-await

5
推荐指数
1
解决办法
4108
查看次数

长期运行任务与线程 - 性能

假设我有一些长期运行的后台工作.每个工作都会做一些工作,然后抓住下一个工作并运行它,并一直持续到时间结束.

目前使用Tasks实现.我有一个JobStream在循环中一次运行一个作业.我可以同时运行5,15或50个这些流,具体取决于负载.

JobManager

public Task Run(CancellationToken cancellationToken) {
    var jobTasks = Enumerable
        .Range(0, _config.BackgroundProcessor.MaximumSimultaneousJobs)
        .Select(o => JobStream.StartNew(..., () => RunNextJob(cancellationToken), cancellationToken));

    return Task.WhenAll(jobTasks);
}
Run Code Online (Sandbox Code Playgroud)

作业流

public static Task StartNew(Func<Task> nextJobRunner, CancellationToken cancellationToken) {
    var jobStream = new JobStream(nextJobRunner, cancellationToken);

    return jobStream.Start();
}

private Task Start() {
    return Task.Run(async () => {
        do {
            await _nextJobRunner();
        } while (!_cancellationToken.IsCancellationRequested);
    });
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,这里的任务是一个很好的举动,还是我应该用老式的方式创建线程?我最关心的是性能并确保工作可以独立运行而不会被束缚,因为另一个人正在努力工作.

c# performance multithreading task async-await

2
推荐指数
1
解决办法
2284
查看次数

对于 TPL 数据流:如何获取 TransformBlock 生成的所有输出,同时阻塞直到所有输入都已处理完毕?

我向单个数据库同步提交一系列select语句(查询 - 数千个),并DataTable为每个查询返回一个语句(注意:该程序仅在运行时了解其正在扫描的数据库模式,因此指某东西的用途DataTables)。该程序在客户端计算机上运行并连接到远程计算机上的数据库。运行这么多查询需要很长时间。因此,假设异步或并行执行它们会加快速度,我正在探索TPL Dataflow (TDF)。我想使用该TDF库,因为它似乎可以处理与编写多线程代码相关的所有问题,否则需要手动完成。

显示的代码基于http://blog.i3arnon.com/2016/05/23/tpl-dataflow/。它很小,只是帮助我理解 的基本操作TDF。请知道我已经阅读了很多博客并编写了很多迭代代码来尝试解决这个问题。

尽管如此,在当前的迭代中,我有一个问题:

问题

代码位于一个button click方法内部(用户使用 UI 选择一台机器、一个 SQL 实例和一个数据库,然后开始扫描)。带有运算符的两行在await构建时返回错误:The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'。我无法更改按钮单击方法的返回类型。我是否需要以某种方式将button click方法与async-await代码隔离?

问题

尽管我找到了描述 的基础知识的漂亮文章TDF,但我找不到如何获取每次调用所产生的输出TransformBlock(即 a DataTable)的示例。虽然我想提交查询async,但我确实需要阻塞,直到提交的所有查询都TransformBlock完成。在所有查询完成之前,如何获取and 块 …

c# task-parallel-library tpl-dataflow

1
推荐指数
1
解决办法
1613
查看次数