gpt4 book ai didi

c# - 没有 UI 线程的任务同步

转载 作者:太空狗 更新时间:2023-10-29 21:55:31 24 4
gpt4 key购买 nike

在下面的代码中,我想同步任务列表结果的报告。这现在正在工作,因为 task.Result 会阻塞直到任务完成。但是,任务 id = 3 需要很长时间才能完成并阻止所有其他已完成的任务报告其状态。

我认为我可以通过将报告 (Console.Write) 移动到 .ContinueWith 指令中来做到这一点,但我没有 UI 线程,所以如何让 TaskScheduler 同步 .ContinueWith 任务?

我现在拥有的:

static void Main(string[] args)
{
Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);

var tasks = new List<Task<int>>();

for (var i = 0; i < 10; i++)
{
var num = i;
var t = Task<int>.Factory.StartNew(() =>
{
if (num == 3)
{
Thread.Sleep(20000);
}
Thread.Sleep(new Random(num).Next(1000, 5000));
Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
return num;
});
tasks.Add(t);
}

foreach (var task in tasks)
{
Console.WriteLine("Completed {0} on {1}", task.Result, Thread.CurrentThread.ManagedThreadId);
}

Console.WriteLine("End of Main");
Console.ReadKey();
}

我想转移到这个或类似的东西,但我需要 Console.Write("Completed...") 全部发生在同一个线程上:

static void Main(string[] args)
{
Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);

for (var i = 0; i < 10; i++)
{
var num = i;
Task<int>.Factory.StartNew(() =>
{
if (num == 3)
{
Thread.Sleep(20000);
}
Thread.Sleep(new Random(num).Next(1000, 10000));
Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
return num;
}).ContinueWith(value =>
{
Console.WriteLine("Completed {0} on {1}", value.Result, Thread.CurrentThread.ManagedThreadId);
}

/* need syncronization context */);
}

Console.WriteLine("End of Main");
Console.ReadKey();
}

-- 解决方案--在获得一些评论并阅读了一些解决方案之后,这是完成我想要的完整解决方案。这里的目标是尽可能快地处理几个长时间运行的任务,然后一次处理每个任务的结果。

static void Main(string[] args)
{
Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);

var results = new BlockingCollection<int>();

Task.Factory.StartNew(() =>
{
while (!results.IsCompleted)
{
try
{
var x = results.Take();
Console.WriteLine("Completed {0} on {1}", x, Thread.CurrentThread.ManagedThreadId);
}
catch (InvalidOperationException)
{
}
}
Console.WriteLine("\r\nNo more items to take.");
});

var tasks = new List<Task>();

for (var i = 0; i < 10; i++)
{
var num = i;
var t = Task.Factory.StartNew(() =>
{
if (num == 3)
{
Thread.Sleep(20000);
}
Thread.Sleep(new Random(num).Next(1000, 10000));
Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
results.Add(num);
});

tasks.Add(t);
}

Task.Factory.ContinueWhenAll(tasks.ToArray(), _ => results.CompleteAdding());

Console.WriteLine("End of Main");
Console.ReadKey();
}

最佳答案

您必须创建某种类型的编写器任务,但是请记住,即使 任务也可以重新安排到另一个 native 或托管线程上!在 TPL 中使用默认调度程序,您无法控制哪个托管线程接收工作。

public class ConcurrentConsole
{
private static BlockingCollection<string> output
= new BlockingCollection<string>();

public static Task CreateWriterTask(CancellationToken token)
{
return new Task(
() =>
{
while (!token.IsCancellationRequested)
{
string nextLine = output.Take(token);
Console.WriteLine(nextLine);
}
},
token);
}

public static void WriteLine(Func<string> writeLine)
{
output.Add(writeLine());
}
}

当我将您的代码切换为使用它时,我收到了以下输出:

End of Main
Done 1 on 6
Completed 1 on 6
Done 5 on 9
Completed 5 on 9
Done 0 on 4
Completed 0 on 4
Done 2 on 5
Completed 2 on 13
Done 7 on 10
Completed 7 on 10
Done 4 on 8
Completed 4 on 5
Done 9 on 12
Completed 9 on 9
Done 6 on 6
Completed 6 on 5
Done 8 on 11
Completed 8 on 4
Done 3 on 7
Completed 3 on 7

即使您的代码将 () => String.Format("Completed {0} on {1}"... 发送到 ConcurrentConsole.WriteLine,确保ManagedThreadId 将在 ConcurrentConsole 任务上获取,它仍然会改变它运行的线程。尽管与执行任务相比可变性较小。

关于c# - 没有 UI 线程的任务同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6550558/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com