使用Progress类:
static async Task MyMethodAsync(IProgress<double> progress = null)
{
int done = 0;
while (done<100)
{
if (progress != null)
progress.Report(done);
done++;
}
}
static async Task CallMyMethodAsync()
{
var progress = new Progress<double>();
progress.ProgressChanged += (sender, args) =>
{
Console.WriteLine("progr " + args);
};
await MyMethodAsync(progress);
}
public static void Main()
{
CallMyMethodAsync();
Console.WriteLine("done with caller");
Console.ReadLine();
}
输出输出不正确:
done with caller
progr 2
progr 3
progr 4
progr 5
progr 6
progr 7
progr 8
progr 9
progr 10
progr 12
progr 11
progr 0
progr 13
progr 16
progr 17
progr 18
progr 19
progr 20
progr 21
progr 22
progr 23
progr 24
progr 25
progr 26
为什么以及如何实现正确的订单?
答案 0 :(得分:0)
Progress<T>
类是异步的。它报告了不同线程的进度,因为它是一个控制台应用程序,正如HashMap所解释的那样:
那些没有同步上下文,因此在线程池上提供了进度回调。因此,您不知道他们何时会被安排,并且多个回调可能同时在线,然后竞争控制台锁实际执行他们的写作
您可以自己实现IProgress<T>
,这是同步的。使用这个:
public class MyProgress<T> : IProgress<T>
{
public event ProgressChangedEventHandler<T> ProgressChanged;
public void Report(T value)
{
ProgressChanged?.Invoke(this, value);
}
}
public delegate void ProgressChangedEventHandler<T>(object sender, T progress);
您只需将您的主叫代码更改为:
var progress = new MyProgress<double>();
答案 1 :(得分:0)
你的意思&#34;阻止并完成......&#34;。
Progress类是异步的。它报告了不同线程的进度,因为它是一个控制台应用程序,正如Damien_The_Unbeliever解释的那样:
这篇文章应该解释为什么你可以'失去&#34;一些电话。
我觉得我的应用程序的细节还很远,但简单的问题是你真的需要为此提供多线程解决方案吗?
如果你真的需要在其他线程和更新UI中执行进程,你可以使用下一个逻辑:
class Class1
{
public delegate void ProcessProgressEventHandler(int progress);
public ProcessProgressEventHandler ProcessProgress;
public EventHandler ProcessEnd;
public void StartHeavyProcess()
{
System.Threading.Thread vThread = new System.Threading.Thread(HeavyProcess);
ProcessProgress += OnProgress;
ProcessEnd += OnProcessEnd;
vThread.Start();
}
private void OnProcessEnd(object sender, EventArgs e)
{
Console.WriteLine("Process end!");
}
private void OnProgress(int progress)
{
Console.WriteLine("Progress: " + progress.ToString());
}
public void HeavyProcess()
{
int done = 0;
while (done < 100)
{
if (ProcessProgress != null)
ProcessProgress(done);
done++;
}
if (ProcessEnd != null)
ProcessEnd(this, new EventArgs());
}
}
P.S。注意,如果你的处理程序调用windows控件moethods你必须在UI线程中调用方法!
答案 2 :(得分:-1)
您获得的结果是因为您使用了启动新线程的任务。
public static void Main()
{
CallMyMethodAsync();
Console.WriteLine("done with caller");
Console.ReadLine();
}
例如第一个命令'CallMyMethodAsync();'只需启动新进程和下一个命令'Console.WriteLine(“使用调用者完成”);'在第一步开始流程结束之前执行。 如果要在第1行开始处理结束后从第2行执行命令,则为:
public static void Main()
{
CallMyMethodAsync()**.Wait();**
Console.WriteLine("done with caller");
Console.ReadLine();
}
答案 3 :(得分:-1)
好的,原因是你使用&#34;事件&#34;但是&#34;事件调度员&#34;不保证按时间顺序处理事件。
我知道的最简单的解决方案是使用委托来告知进度:
static async Task MyMethodAsync(Action<double> progress = null)
{
int done = 0;
while (done<100)
{
if (progress != null)
progress.Invoke(done);
done++;
}
}