在 .Net Core 的另一个线程上调用函数
Posted
技术标签:
【中文标题】在 .Net Core 的另一个线程上调用函数【英文标题】:Invoking function on another thread in .Net Core 【发布时间】:2021-07-19 17:04:51 【问题描述】:我有一个后台线程有一个长时间运行的任务。
后台线程根据给定的过滤器搜索文件。 该任务可能运行很长时间,所以我不想等待任务完成才能显示一些结果。
此外,我不想锁定我的 UI 线程以检查后台任务是否有新结果。
我宁愿通知我的主线程:“嘿,添加了一个新的搜索结果”。 有点像 Windows 资源管理器,在搜索仍在进行时显示搜索结果:
foreach (FileInfo itemToFilter in unfilteredSearchResults)
if (extension == ".wav" || extension == ".flac" || extension == ".mp3")
// read audio information such as tags etc. Might take some time per file
WaveFileLib.WaveFile.WAVEFile audioItem = new WaveFileLib.WaveFile.WAVEFile(audioFile.FullName);
// Compare audio information such as tags, title, license, date, length etc to filter
if (Filter.AudioItemMatchesFilter(ref audioItem))
lock (threadLock)
// add search result to list of filtered audio files
this.AudioItemList.Add(audioItem);
// notify main thread in order to refresh ui (if applicable)
ParentView.AudioItemAdded();
然后主线程可以从新添加的项目生成视图。
以前,使用 BeginInvoke
很容易做到这一点,但使用 .net core 时,这种可能性似乎消失了。
通知主线程更新搜索结果的替代方案/选项是什么?
【问题讨论】:
使用Progress 类。它就是为了这个原因而创建的 【参考方案1】:正如 Panagiotis Kanavos 所说的
public class AudioFileSearcher
// task caller
public AudioFileSearcher(string searchPath, bool includeSubFolders, Views.SoundListView.SoundList parentView)
this.progress1 = new Progress<int>(
backgroundWorker1_ProgressChanged();
);
Task.Run(async () => await FindAudioFiles(progress1));
// reference to be updated by task and read by event Handler
private Progress<int> progress1 get; set;
// do something on task progress
void backgroundWorker1_ProgressChanged()
// Update UI on main thread or whatever
// Task
public async Task FindAudioFiles(IProgress<int> progress)
foreach(AudioItem itemToProcess in allFoundaudioItems)
// do long processing in background task
// a new element has been generated, update UI
if (progress != null) progress.Report(0); // ~fire event
像魅力一样工作,正在加载物品
【讨论】:
【参考方案2】:您应该使用 Microsoft 的响应式框架(又名 Rx)- NuGet System.Reactive
并添加 using System.Reactive.Linq;
- 然后您可以这样做:
IObservable<WaveFileLib.WaveFile.WAVEFile> query =
from itemToFilter in unfilteredSearchResults.ToObservable()
where extension == ".wav" || extension == ".flac" || extension == ".mp3"
from audioItem in Observable.Start(() => new WaveFileLib.WaveFile.WAVEFile(audioFile.FullName))
from x in Observable.Start(() =>
var a = audioItem;
var flag = Filter.AudioItemMatchesFilter(ref a);
return new flag, audioItem = a ;
)
where x.flag
select x.audioItem;
IDisposable subscription =
query
.ObserveOnDispatcher()
.Subscribe(audioItem =>
/* Your code to update the UI here */
);
我不清楚是创建一个新的WAVEFile
还是调用AudioItemMatchesFilter
需要时间,所以我将两者都包裹在Observable.Start
中。你还打了一个ref
电话,这让代码有点乱。
尽管如此,此代码在后台处理所有调用,并在结果进入调度程序线程时自动将它们移动。
【讨论】:
以上是关于在 .Net Core 的另一个线程上调用函数的主要内容,如果未能解决你的问题,请参考以下文章
CoInitialize() 是不是总是在每个 .Net Framework / .Net Core 线程上隐式调用?
如何在 .net Core API 项目中跨多个线程限制对 HttpClient 的所有传出异步调用
Asp .Net Core WebApi:异常的第二次http调用