TPL使用任务计划程序来协调任务.根据官方文档,默认任务调度程序使用线程池,但如果显示TaskCreationOptions.LongRunning选项,则它将为该任务创建专用线程(A).
问题:截至目前,Visual Studio 2010的MSDN文档尚未就绪,当前的在线MSDN尚未最终确定; 有谁知道(A)是真还是假?
c# scheduled-tasks .net-4.0 threadpool task-parallel-library
Web和Stack Overflow中有很多地方不鼓励改变ThreadPool线程或TPL 任务的优先级.特别是:
"你无法控制线程池线程的状态和优先级."
"运行时管理线程池.您无法控制线程的调度,也无法更改线程的优先级."
"你不应该改变PoolThread的文化或优先级......或者就像你没有画出或重新装修租赁汽车一样."
"在某些情况下,创建和管理自己的线程而不是使用线程池线程是合适的:(例如...)您需要一个线程具有特定的优先级."
"ThreadPool中的每个线程都以默认优先级运行,而更改ThreadPriority的代码无效."
但是,这样做很简单,调试器显示更改似乎确实存在(只要值可以回读).
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
Run Code Online (Sandbox Code Playgroud)
所以问题是,这个禁忌的具体原因是什么?
我怀疑:这样做会扰乱游泳池的微妙负载平衡假设.但这并不能解释为什么有些消息来源说你无法改变它.
我正在寻找有关火灾最佳实践的信息并忘记asp.net mvc行动...基本上我想要一个移动客户端来打电话; 服务器启动异步任务; 然后尽快返回移动客户端.
但我想确保,假设没有异常,异步任务将成功完成.显然有几个不同的选择:
我认为任务将是这里的最佳选择,但想从SO获得想法.
编辑:根据已有的一些答案澄清:客户端不需要回复.我希望一旦服务器开始异步任务,HTTP请求就会尽快完成.我知道客户端上的异步模式,但是我想限制移动设备维持连接打开所需的时间.此外,希望避免有一个单独的进程轮询或推送消息(通过队列,总线等),因为这是过度的.我只想在数据库中记录某些内容,在IO完成之前,客户端不需要保持连接.
对于需要使用.Net 4中的Task API运行的后台线程,这是一个很好的设计吗?我唯一担心的是,如果我们要取消该任务,我将如何做到这一点?我知道我可以设置ProgramEnding,true但我知道CancellationTokenTask API中有一个.
这只是一个示例代码示例,以便一个线程将添加到集合中,另一个线程将从中删除.任务设置为LongRunning,因为这需要在程序运行时连续运行
private void RemoveFromBlockingCollection()
{
while (!ProgramEnding)
{
foreach (var x in DataInQueue.GetConsumingEnumerable())
{
Console.WriteLine("Task={0}, obj={1}, Thread={2}"
, Task.CurrentId, x + " Removed"
, Thread.CurrentThread.ManagedThreadId);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
DataInQueue = new BlockingCollection<string>();
var t9 = Task.Factory.StartNew(RemoveFromBlockingCollection
, TaskCreationOptions.LongRunning);
for (int i = 0; i < 100; i++)
{
DataInQueue.Add(i.ToString());
Console.WriteLine("Task={0}, obj={1}, Thread={2}",
Task.CurrentId, i + " Added",
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(100);
}
ProgramEnding = true; …Run Code Online (Sandbox Code Playgroud) 可能是一个微不足道的问题,但它可能有助于我的基本理解.
以下两个实现之间是否有任何重要区别?
Task.Factory.StartNew:
public Task<string> ReadAllTextAsync(string path) {
return Task.Factory.StartNew(() => File.ReadAllText(path));
}
Run Code Online (Sandbox Code Playgroud)异步方法StreamReader:
public async Task<string> ReadAllTextAsync(string path) {
using (var stream = File.OpenRead(path))
using (var reader = new StreamReader(stream)) {
return await reader.ReadToEndAsync();
}
}
Run Code Online (Sandbox Code Playgroud)我有一个使用.NET 4.0的C#控制台应用程序项目,安装了Microsoft.Bcl.Async软件包.我用这个代码:
internal class Program
{
private static void Main(string[] args)
{
Foo().Wait();
}
static void Log(Exception ex)
{
}
private static async Task Foo()
{
try
{
await DoSomething();
}
catch (Exception ex)
{
Log(ex);
}
}
private static async Task DoSomething()
{
throw new DivideByZeroException();
}
}
Run Code Online (Sandbox Code Playgroud)
如果我在Log方法中放置一个断点,我得到了DivideByZero异常,但我看到的堆栈跟踪是:
at Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.GetResult()
at AsyncStacks.Program.<Foo>d__0.MoveNext() in p:\Sandbox\AsyncStacks\AsyncStacks\Program.cs:line 25
Run Code Online (Sandbox Code Playgroud)
这个堆栈跟踪几乎没用,因为它没有告诉我实际抛出异常的位置.
如果我将项目更改为目标.NET 4.5,我会得到一个更有用的异常:
at AsyncStacks.Program.<DoSomething>d__3.MoveNext() in p:\Sandbox\AsyncStacks\AsyncStacks\Program.cs:line 35
--- End of stack trace from …Run Code Online (Sandbox Code Playgroud) c# asynchronous exception-handling task-parallel-library async-await
我有以下代码:
List<Task<bool>> tasks = tasksQuery.ToList();
while (tasks.Any())
{
Task<bool> completedTask = await Task.WhenAny(tasks);
if (await completedTask)
return true;
tasks.Remove(completedTask);
}
Run Code Online (Sandbox Code Playgroud)
它并行启动任务.当第一个完成的任务返回true时,方法返回true.
所有剩余的任务已经启动并且可能仍然在后台运行会发生什么? 这是执行异步,并行和在第一个条件发生后应该返回的代码的正确方法,还是最好逐个启动它们并等待单独进行?
谢谢
我有一个创建一些任务的方法,然后在返回之前用WaitAll等待它们.问题是,如果这些任务被取消,那么WaitAll会抛出一个包含大量TaskCanceledException的AggregateException.
这意味着WaitAll将在两种不同的情况下抛出异常:
后者完全符合一个令人烦恼的例外的定义:它是一个完全非特殊情况下抛出的异常,所以我必须抓住它才能恢复正常的控制流程.幸运的是,它很容易捕获,对吧?只需添加catch (AggregateException)- 哦等等,这是在发生致命错误时被抛出的相同类型.
我需要在返回之前等待任务完成运行(我需要知道他们不再使用他们的数据库连接,文件句柄或其他任何东西),所以我确实需要WaitAll或类似的东西.如果任何任务出现故障,我确实希望这些异常作为未处理的异常传播.我只是不想要取消的例外.
如何防止WaitAll为已取消的任务抛出异常?
在这个问题中,Stephen Cleary接受的答案是LogicalCallContext无法正常使用异步.他还在这个 MSDN主题中发布了它.
LogicalCallContext保存一个Hashtable,存储发送到CallContext.LogicalGet/SetData的数据.它只是这个Hashtable的浅层副本.因此,如果您在其中存储可变对象,则不同的任务/线程将看到彼此的更改.这就是Stephen Cleary的示例NDC程序(在MSDN线程上发布)无法正常工作的原因.
但是AFAICS,如果你只在Hashtable中存储不可变数据(可能通过使用不可变集合),那应该有效,让我们实现一个NDC.
然而,Stephen Cleary也在接受的答案中说:
CallContext不能用于此.Microsoft特别建议不要使用CallContext进行远程处理以外的任何操作.更重要的是,逻辑CallContext不了解异步方法如何早期返回并稍后恢复.
不幸的是,该建议的链接已关闭(找不到页面).所以我的问题是,为什么不推荐这个?为什么我不能以这种方式使用LogicalCallContext?说它不理解异步方法是什么意思?从调用者的POV,他们只是返回任务的方法,不是吗?
ETA:另见其他问题.在那里,Stephen Cleary的答案说:
你可以使用CallContext.LogicalSetData和CallContext.LogicalGetData,但我建议你不要,因为当你使用简单的并行性时它们不支持任何类型的"克隆"
这似乎支持我的情况.所以我应该能够建立一个NDC,这实际上是我需要的,而不是log4net.
我写了一些示例代码,它似乎工作,但仅仅测试并不总是捕获并发错误.所以,由于其他帖子中有提示这可能不起作用,我仍然会问:这种方法有效吗?
ETA:当我从下面的答案中运行斯蒂芬提出的复制品时,我没有得到错误的答案,他说我会,我得到正确的答案.即使他说"这里的LogicalCallContext值总是"1"",我总是得到0的正确值.这可能是因为竞争条件?无论如何,我还没有在我自己的电脑上复制任何实际问题.这是我正在运行的确切代码; 它只在这里打印"真实",斯蒂芬说至少在某些时候应该打印"假".
private static string key2 = "key2";
private static int Storage2 {
get { return (int) CallContext.LogicalGetData(key2); }
set { CallContext.LogicalSetData(key2, value);}
}
private static async Task ParentAsync() {
//Storage = new Stored(0); // Set LogicalCallContext value to "0".
Storage2 = 0;
Task childTaskA = ChildAAsync();
// LogicalCallContext value here is always …Run Code Online (Sandbox Code Playgroud) 我在WinForms应用程序中有以下代码,只有一个按钮和一个标签:
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
await Run();
}
private async Task Run()
{
await Task.Run(async () => {
await File.AppendText("temp.dat").WriteAsync("a");
label1.Text = "test";
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我正在研究的实际应用程序的简化版本.我的印象是,通过在我使用async/await Task.Run我可以设置label1.Text属性.但是,当运行此代码时,我得到错误,我不在UI线程上,我无法访问该控件.
为什么我无法访问标签控件?
c# ×7
async-await ×5
.net ×3
.net-4.0 ×2
asynchronous ×2
threadpool ×2
asp.net-mvc ×1
cancellation ×1
task ×1
winforms ×1