如何在不等待事件监听器运行的情况下触发事件?

时间:2023-01-02 23:58:50

I have a question about events in .NET (C#). I have had to write code for several situations in which I have a background task running and I want to notify a main thread, or controller class, that something has occurred, such as task completed, or finished copying a file, but I don't want the background task to wait for the main thread's delegate to process the event.

我对.NET(C#)中的事件有疑问。我必须编写代码,用于运行后台任务的几种情况,并且我想通知主线程或控制器类已发生某些事情,例如任务已完成,或已完成复制文件,但我不知道t希望后台任务等待主线程的委托处理事件。

I want to do something like message passing: Send the message, but who cares what they do with it.

我想做一些像消息传递这样的事情:发送消息,但谁在乎他们用它做什么。

For example:

A class is written to process several processes in sequence, one after the other. Each process needs to run on a background thread. When work is completed, an event fires and tells the controller that it's done (let's say using OnCompleted() method)

编写一个类来按顺序处理多个进程,一个接一个。每个进程都需要在后台线程上运行。当工作完成时,事件触发并告诉控制器它已完成(假设使用OnCompleted()方法)

The problem is that if the controller's event handler is used to start the subsequent process, the previous processes' OnComplete method stays on the call stack (never finishes executing) until the all of the processes have completed.

问题是如果控制器的事件处理程序用于启动后续进程,则先前进程的OnComplete方法将保留在调用堆栈上(永远不会完成执行),直到所有进程完成为止。

In that situation, how could the background task notify the controller class that the work is done without keeping the event raising method on the stack?

在那种情况下,后台任务如何通知控制器类工作完成而不将事件提升方法保留在堆栈上?

Example 2: A backup program.

示例2:备份程序。

A background thread runs to copy each file to the destination. The background needs to notify the UI the last file that was copied, but it doesn't need to wait for the UI to update. Instead, it just wants to say, "BTW, here's some info. Now, let me get back to work." The event listener shouldn't block the processing of the event raiser.

后台线程运行以将每个文件复制到目标。后台需要通知UI最后复制的文件,但不需要等待UI更新。相反,它只是想说,“顺便说一下,这里有一些信息。现在,让我重新开始工作。”事件监听器不应阻止事件提升者的处理。

4 个解决方案

#1


You could do an async invoke when raising the event (as mentioned), or just raise the event itself on a background thread:

在引发事件时(如上所述),您可以执行异步调用,或者只在后台线程上引发事件本身:

void OnUpdated(EventArgs e) {
   EventHandler h = this.Updated;
   if (h != null) h(e);
}

void DoStuff() {
   BigMethod();
   ThreadPool.QueueUserWorkItem(OnUpdated, EventArgs.Empty);
   BigMethod2();
}

If you raise asynchronously, multiple listeners would be processing your event at the same time. At the very least, that requires a thread-safe EventArg class. If you expect them to interact with your class as well, then you should document very carefully or make it thread-safe as well.

如果异步引发,多个侦听器将同时处理您的事件。至少,这需要一个线程安全的EventArg类。如果您希望它们也与您的班级进行交互,那么您应该非常仔细地记录或者使其成为线程安全的。

Raising the event on a background thread carries the same caveats for your class methods, but you don't have to worry about the EventArgs class itself.

在后台线程上引发事件对类方法有相同的警告,但您不必担心EventArgs类本身。

#2


It sounds like you are trying to invoke the delegates in the event's invocation list asynchronously.

听起来你正试图异步调用事件的调用列表中的委托。

I would suggest that you read .NET Asynchronous Events To Send Process Status To User Interface:

我建议您阅读.NET异步事件以将进程状态发送到用户界面:

The .NET Framework offers us the concept of raising events (and other items) in our classes asynchronously. This means that we can raise the event in such a way as to not have the subscriber to that event (typically the user interface) hold up the processing in the method that raised the event. The benefit being that it doesn't negatively impact the performance of our business layer method.

.NET Framework为我们提供了异步提升类中事件(和其他项)的概念。这意味着我们可以通过这样一种方式引发事件,即不让该事件的订阅者(通常是用户界面)在引发事件的方法中保持处理。好处是它不会对我们的业务层方法的性能产生负面影响。

#3


Have the first event do nothing but kick off the thread, then it doesn't matter what other event listeners there are.

让第一个事件除了启动线程之外什么都不做,那么其他事件监听器是什么并不重要。

#4


For your case 2 of back up program. The code sample will fire a file copy asynchronously and once the copy is done it calls the call back method. In the callback if you dont want to wait for UI to update, then you will have to call the UI updating code asynchronously

对于你的案例2备份程序。代码示例将异步触发文件副本,一旦完成复制,它将调用回调方法。在回调中,如果您不想等待UI更新,那么您将不得不异步调用UI更新代码

You can use asynchronous delegates

您可以使用异步委托

public class AsyncFileCopier
    {
        public delegate void FileCopyDelegate(string sourceFile, string destFile);

        public static void AsynFileCopy(string sourceFile, string destFile)
        {
            FileCopyDelegate del = new FileCopyDelegate(FileCopy);
            IAsyncResult result = del.BeginInvoke(sourceFile, destFile, CallBackAfterFileCopied, null);
        }

        public static void FileCopy(string sourceFile, string destFile)
        { 
            // Code to copy the file
        }

        public static void CallBackAfterFileCopied(IAsyncResult result)
        {
            // Notify UI by calling an async del (probably using fire & forget approach or another callback if desired)
        }
    }

You can call it as:

你可以称之为:

AsyncFileCopier.AsynFileCopy("abc.txt", "xyz.txt");

This link tells you the different techniques of asyn coding

此链接告诉您asyn编码的不同技术

#1


You could do an async invoke when raising the event (as mentioned), or just raise the event itself on a background thread:

在引发事件时(如上所述),您可以执行异步调用,或者只在后台线程上引发事件本身:

void OnUpdated(EventArgs e) {
   EventHandler h = this.Updated;
   if (h != null) h(e);
}

void DoStuff() {
   BigMethod();
   ThreadPool.QueueUserWorkItem(OnUpdated, EventArgs.Empty);
   BigMethod2();
}

If you raise asynchronously, multiple listeners would be processing your event at the same time. At the very least, that requires a thread-safe EventArg class. If you expect them to interact with your class as well, then you should document very carefully or make it thread-safe as well.

如果异步引发,多个侦听器将同时处理您的事件。至少,这需要一个线程安全的EventArg类。如果您希望它们也与您的班级进行交互,那么您应该非常仔细地记录或者使其成为线程安全的。

Raising the event on a background thread carries the same caveats for your class methods, but you don't have to worry about the EventArgs class itself.

在后台线程上引发事件对类方法有相同的警告,但您不必担心EventArgs类本身。

#2


It sounds like you are trying to invoke the delegates in the event's invocation list asynchronously.

听起来你正试图异步调用事件的调用列表中的委托。

I would suggest that you read .NET Asynchronous Events To Send Process Status To User Interface:

我建议您阅读.NET异步事件以将进程状态发送到用户界面:

The .NET Framework offers us the concept of raising events (and other items) in our classes asynchronously. This means that we can raise the event in such a way as to not have the subscriber to that event (typically the user interface) hold up the processing in the method that raised the event. The benefit being that it doesn't negatively impact the performance of our business layer method.

.NET Framework为我们提供了异步提升类中事件(和其他项)的概念。这意味着我们可以通过这样一种方式引发事件,即不让该事件的订阅者(通常是用户界面)在引发事件的方法中保持处理。好处是它不会对我们的业务层方法的性能产生负面影响。

#3


Have the first event do nothing but kick off the thread, then it doesn't matter what other event listeners there are.

让第一个事件除了启动线程之外什么都不做,那么其他事件监听器是什么并不重要。

#4


For your case 2 of back up program. The code sample will fire a file copy asynchronously and once the copy is done it calls the call back method. In the callback if you dont want to wait for UI to update, then you will have to call the UI updating code asynchronously

对于你的案例2备份程序。代码示例将异步触发文件副本,一旦完成复制,它将调用回调方法。在回调中,如果您不想等待UI更新,那么您将不得不异步调用UI更新代码

You can use asynchronous delegates

您可以使用异步委托

public class AsyncFileCopier
    {
        public delegate void FileCopyDelegate(string sourceFile, string destFile);

        public static void AsynFileCopy(string sourceFile, string destFile)
        {
            FileCopyDelegate del = new FileCopyDelegate(FileCopy);
            IAsyncResult result = del.BeginInvoke(sourceFile, destFile, CallBackAfterFileCopied, null);
        }

        public static void FileCopy(string sourceFile, string destFile)
        { 
            // Code to copy the file
        }

        public static void CallBackAfterFileCopied(IAsyncResult result)
        {
            // Notify UI by calling an async del (probably using fire & forget approach or another callback if desired)
        }
    }

You can call it as:

你可以称之为:

AsyncFileCopier.AsynFileCopy("abc.txt", "xyz.txt");

This link tells you the different techniques of asyn coding

此链接告诉您asyn编码的不同技术