在 .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 线程上隐式调用?

如何从Angular 6中的另一个类调用类中的函数?

如何在 .net Core API 项目中跨多个线程限制对 HttpClient 的所有传出异步调用

Asp .Net Core WebApi:异常的第二次http调用

在 asp.net core 5 MVC 视图中从 C# 代码调用 JavaScript 函数

从 ASP.NET Core Blazor 中的 .NET 方法调用 JavaScript 函数