use*_*870 0 .net c# task winforms task-parallel-library
我有接收文件列表的功能,并在单个/单独的线程中工作:
public void DoWork(params...)
{
_filesInProcess = 0;
_filesFinished = 0;
_tokenSource = new CancellationTokenSource();
var token = _tokenSource.Token;
Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach(_indexedSource,
new ParallelOptions
{
MaxDegreeOfParallelism = parallelThreads //limit number of parallel threads
},
file =>
{
if (token.IsCancellationRequested)
return;
//do work...
});
}
catch (Exception)
{ }
}, _tokenSource.Token).ContinueWith(
t =>
{
//finish...
if (OnFinishWorkEventHandler != null)
OnFinishWorkEventHandler(this, EventArgs.Empty);
}
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
}
Run Code Online (Sandbox Code Playgroud)
我添加了在循环中运行此命令的选项,在此函数完成后从主窗体运行,如果我需要另一个循环,我再次调用此函数,但在第二次冻结我的所有UI,我无法找到原因
这就是我调用我的函数的方式:
private void StartJob()
{
string[] files = GetlFiles().ToArray();
Job job = new Job(files);
timerStatus.Enabled = true;
job.OnStartPlayEventHandler += job_OnStartPlayEventHandler;
job.OnFinishPlayEventHandler += job_OnFinishPlayEventHandler;
job.OnFinishWorkEventHandler += job_OnFinishWorkEventHandler;
job.StartTimerEventHandler += job_StartTimerEventHandler;
job.StopTimerEventHandler += job_StopTimerEventHandler;
job.DoWork(
NetworkAdapter.SelectedAdapter.PacketDevice,
ReadSpeed(),
PlayOption.Regular,
ChecksumFixer.FixBadChecksum,
ReadParallelThreads(PlayState.Single),
Iteration.Loops
);
}
Run Code Online (Sandbox Code Playgroud)
完成此操作后:
private void job_OnFinishWorkEventHandler(object sender, EventArgs e)
{
Job job = sender as Job;
job.OnStartPlayEventHandler -= job_OnStartPlayEventHandler;
job.OnFinishPlayEventHandler -= job_OnFinishPlayEventHandler;
job.OnFinishWorkEventHandler -= job_OnFinishWorkEventHandler;
job.StartTimerEventHandler -= job_StartTimerEventHandler;
job.StopTimerEventHandler -= job_StopTimerEventHandler;
Iteration.LoopFinished++;
if (Iteration.LoopFinished < Iteration.Loops) // In case i want another loop
StartJob();
else
{
UnlockButtonsAfterPlay();
UnlockContextMenuAfterPlay();
}
}
Run Code Online (Sandbox Code Playgroud)
而正如我提到的所有卡在第二次迭代
Task.Factory.StartNew很危险.它使用TaskScheduler.Current而不是TaskScheduler.Default.
在你的情况下OnFinishWorkEventHandler被触发从ContinueWithUI线程中运行TaskScheduler.FromCurrentSynchronizationContext().所以那时TaskScheduler.Current是UIScheduler而不是TaskScheduler.Default(threadpool scheduler).这就是为什么你的第二个任务在UI线程中安排,导致UI冻结.
解决这个Task.Run总是指向的用法TaskScheduler.Default.Task.Run是.net 4.5中的新功能,如果你在.net 4.0中,你可以创建你TaskFactory的默认参数,你可以使用它.
private static readonly TaskFactory factory = new TaskFactory(CancellationToken.None,
TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
Run Code Online (Sandbox Code Playgroud)
然后用
factory.StartNew(...);
Run Code Online (Sandbox Code Playgroud)
如果您只是在自己不需要创建工厂实例时才使用它,那么只需TaskScheduler明确指定即可.
Task.Factory.StartNew(() =>{
//Your code here
}, _tokenSource.Token,
TaskCreationOptions.None,
TaskScheduler.Default)//Note TaskScheduler.Default here
.ContinueWith(
t =>
{
//finish...
if (OnFinishWorkEventHandler != null)
OnFinishWorkEventHandler(this, EventArgs.Empty);
}
, TaskScheduler.FromCurrentSynchronizationContext());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
524 次 |
| 最近记录: |