我正在编写一个程序,演示在服务器可伸缩性上下文中使用异步IO的好处。程序并发地使用一个异步方法,然后报告参与异步处理的线程的ID。
为了说明,请考虑以下内容:
static async Task<TimeSpan> AsyncCalling(TimeSpan time)
{
using (SleepService.SleepServiceClient client = new SleepService.SleepServiceClient())
{
TimeSpan response = await client.SleepAsync(time);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
response += await client.SleepAsync(TimeSpan.FromTicks(time.Ticks / 2));
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
return response;
}
}
int numberOfWorkItems = 50;
for (int i = 0; i < numberOfWorkItems; ++i)
{
TimeSpan value = TimeSpan.FromSeconds((i % 3) + 1);
ThreadPool.QueueUserWorkItem(arg => { TimeSpan t = AsyncCalling(value).Result; });
Thread.Sleep(300);
}
static Task<TimeSpan> TaskAsyncCalling(TimeSpan time)
{
SleepService.SleepServiceClient client = new SleepService.SleepServiceClient();
return client.SleepAsync(time)
.ContinueWith(t =>
{
TimeSpan result = t.Result;
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
return client.SleepAsync(TimeSpan.FromTicks(time.Ticks / 2))
.ContinueWith(t1 =>
{
result += t1.Result;
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
(client as IDisposable).Dispose();
return result;
});
})
.Unwrap();
}
在同一上下文中调用taskasyncalling
时,输出结果完全不同。这些任务通常需要更长的时间来执行,并且唯一线程ID的总数通常在30个左右(同样,对于我的2核机器)。
为什么会出现这种差距呢?我知道await
不是task
的普通包装,但是线程池是共同的分母,我希望在TPL实现中也能出现同样聪明的线程重用。
有没有另一种方法可以重写TPL方法,以达到相同的结果而不阻塞?
public TimeSpan Sleep(TimeSpan time)
{
Thread.Sleep(time);
return time;
}
在这种情况下,经典TPL版本比async/await
版本使用更多的线程,因为每个continuewith
延续都是在单独的池线程上执行的。
使用TaskContinuationSoptions.ExecuteSynchronology
修复此问题:
static Task<TimeSpan> TaskAsyncCalling(TimeSpan time)
{
SleepService.SleepServiceClient client = new SleepService.SleepServiceClient();
return client.SleepAsync(time)
.ContinueWith(t =>
{
TimeSpan result = t.Result;
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
return client.SleepAsync(TimeSpan.FromTicks(time.Ticks / 2))
.ContinueWith(t1 =>
{
result += t1.Result;
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
(client as IDisposable).Dispose();
return result;
}, TaskContinuationsOptions.ExecuteSynchronously);
}, TaskContinuationsOptions.ExecuteSynchronously)
.Unwrap();
}
OTOH,await
连续操作通常是同步执行的(如果操作是在同一同步上下文上完成的,或者如果在两个执行点都没有同步)。所以它需要少获取两个线程。
一个很好的相关阅读:“为什么是TaskContinuationSoptions.ExecuteSynchronology opt-in?”
最近在接受采访时,我得到了这个问题。 Q: 您编写过多线程应用程序吗? 甲:是的 问:介意解释更多吗? 答:我使用了< code>Tasks(任务并行库)来执行一些任务,比如< code >加载UI时等待来自互联网的一些信息。这提高了我的应用程序的可用性。 问:但是,仅仅您使用了就意味着您编写了应用程序? 我:(不知道该说什么) 那么,究竟什么是多线程应用程序?它与使用不同吗?
问题内容: 我最近继承了一个小型Java程序,该程序从大型数据库中获取信息,进行一些处理并生成有关该信息的详细图像。原始作者使用单个线程编写了代码,然后对其进行了修改,以使其可以使用多个线程。 他在代码中定义了一个常量; 然后,它设置用于创建映像的线程数。 我理解他的理由,即线程数不能大于可用处理器的数目,因此将其设置为可以充分发挥处理器潜力的数量。这样对吗?还是有更好的方法来充分利用处理器的潜力
我最近使用vert. x(基于java)测试了一个简单的HTTP服务器。我对超文本传输协议服务器的吞吐量和api延迟感到惊讶,它非常快。 超文本传输协议-server的同一段代码在java应用程序上以单线程运行,无锁且无阻塞。性能不到vert. x 1的三分之一。 我不明白的是,vert. x优于非反应性java应用程序的核心技术区别是什么? 统计数据: 测试是使用Jmeter完成的。jmetm和
我正在使用多个线程在不同的表中插入插入记录。此外,我正在使用批处理的记录插入,以提高效率。 注意:要插入的记录数以百万为单位。 我的问题是,在这种多线程环境中,我应该使用连接池吗? 我关心的问题: 每个线程将运行相当长的时间来执行数据库操作。所以,如果我的连接池的大小是2,线程的数量是4,那么在给定的时刻只有2个线程将运行。因此,其他两个线程将会在很长一段时间内保持理想状态以获得连接,因为针对百万
我的工作与Javawebapp与Apache Tomcat一起运行。Tomcat线程池的最大线程数为800,minSpareThread为25。当它运行时,它通常在给定时间运行大约400个线程。 比方说,我有一个计算成本很高的非阻塞任务,我必须在我的Tomcat应用程序中完成,在这个应用程序中,ForkJoinPool。commonPool用于更有效地解决任务。 因为我的ApacheTomcat应
问题内容: 在Java中拥有多个线程池的优缺点是什么?我已经看过代码,其中有多个线程池用于不同的“类型”任务,而且我不确定它是更好的设计还是只是开发人员感到懒惰。一个示例是将ScheduledThreadPoolExecutor用于定期执行的任务或具有超时的任务,而将另一ThreadPoolExecutor用于其他任务。 问题答案: 具有单独的专用线程池的目的是,使活动不会因线程不足而被饥饿,因为