简体   繁体   English

如果异步引发事件,是否起作用?

[英]Do events work if raised asynchronously?

I have the following skeleton of a class. 我有以下课程的骨架。 As you can see in the TODO: comment I will be implementing an AsyncEnumerator construct here. 如您在TODO:注释中所见,我将在这里实现AsyncEnumerator构造。 This method will grab a request and pass the data off to another method to be proccessed. 该方法将捕获一个请求,并将数据传递给另一个要处理的方法。 Based on the process I would like to call the events, either SendMilestoneReached or SendFailed. 基于该过程,我想将事件称为SendMilestoneReached或SendFailed。 I am worried these may happen on a different thread due to the AsyncEnumerator. 我担心由于AsyncEnumerator这些可能会在不同的线程上发生。

Will this have an effect on the UI thread where the Webtext class will be called? 这会对将调用Webtext类的UI线程产生影响吗?

/// <summary>
/// Sends Webtexts.
/// </summary>
public class Webtext
{
    #region Event Definitions

    // Events.
    public event EventHandler<SendingEventArgs> SendStarted = delegate { };
    public event EventHandler<SendingEventArgs> SendFailed = delegate { };
    public event EventHandler<SendingEventArgs> SendSuccessful = delegate { };
    public event EventHandler<SendingEventArgs> SendMilestoneReached = delegate { };

    // Shared EventArgs Object, Consumed by the Events.
    SendingEventArgs EventArgs = new SendingEventArgs();

    #endregion

    /// <summary>
    /// Executes the send request.
    /// </summary>
    /// <param name="Operator">The operator whos service to use.</param>
    /// <param name="Username">The username of the requested operator.</param>
    /// <param name="Password">The password of the requested operator.</param>
    /// <param name="Content">The content to send.</param>
    /// <param name="Recipient">The recipient to recieve the content.</param>
    public void ExecuteSendRequest(string Operator, 
                                   string Username, 
                                   string Password, 
                                   string Content, 
                                   string Recipient)
    {
        //TODO: Implement Async requests here.
    }

    #region Event Handlers

    /// <summary>
    /// Called when [sending started].
    /// </summary>
    protected void OnSendingStarted()
    {
        SendStarted(this, EventArgs);
    }

    /// <summary>
    /// Called when [send fail].
    /// </summary>
    protected void OnSendFail()
    {
        SendFailed(this, EventArgs);
    }

    /// <summary>
    /// Called when [send successful].
    /// </summary>
    protected void OnSendSuccessful()
    {

        SendSuccessful(this, EventArgs);
    }

    /// <summary>
    /// Called when [send milestone reached].
    /// </summary>
    protected void OnSendMilestoneReached()
    {
        SendMilestoneReached(this, EventArgs);
    }

    #endregion


}

Event is created by the same Thread that has raised it. 事件是由引发该事件的同一Thread创建的。 This principle sounds simple but important to know. 这个原理听起来很简单,但很重要。

So: 所以:

Scenario 1 App is opened. 方案1应用已打开。 Webtext is initialised by the form in the UI thread and its send is called. Webtext由UI线程中的表单初始化,并调用其发送。 Webtext sends the request synchronously and fires the event. Webtext 同步发送请求并触发事件。 During the whole time, all operation is done on the UI thread. 在整个过程中,所有操作都在UI线程上完成。

Scenario 2 App is opened. 方案2应用已打开。 Webtext is initialised by the form in the UI thread and its send is called. Webtext由UI线程中的表单初始化,并调用其发送。 Webtext sends the request Asynchronously using a worker thread. Webtext使用辅助线程异步发送请求。 Second thread fires the event when it is finished. 第二线程在事件结束时触发该事件。 This will be the worker thread (background or foreground depending on the how you create the thread). 这将是工作线程(后台还是前台,具体取决于创建线程的方式)。 Any call through this thread to UI elements needs to be done using Invoke . 通过此线程对UI元素的任何调用都需要使用Invoke完成。

As you can see, it very much depends on how you implement the send method. 如您所见, 这很大程度上取决于您如何实现send方法。 I cannot see any implementation of the send itself so all I can say is if you spawn a thread or use threadpool it will be on the worker thread otherwise simply sending synchronously will be on UI thread. 我看不到发送本身的任何实现,因此,我只能说是生成线程还是使用线程池,它将在工作线程上,否则简单地同步发送将在UI线程上。

Note that if you're raising events asynchronously and the handlers need to update the user interface, they'll need to synchronize with the UI thread in order to update any user controls. 请注意,如果您异步引发事件,并且处理程序需要更新用户界面,则它们需要与UI线程同步以便更新任何用户控件。 If you raise events asynchronously, you're placing a larger burden on classes that subscribe to your events: they have to know how to do the UI thread synchronization. 如果异步引发事件,那么将给订阅事件的类带来更大的负担:它们必须知道如何执行UI线程同步。

For me, in general , I've found that asynchronous events aren't worth the trouble because almost invariably I end up having to handle those events in UI programs. 对于我来说, 总的来说 ,我发现异步事件是不值得的,因为我几乎总是不得不在UI程序中处理那些事件。 I came to the conclusion that if I want events handled asynchronously, then the handler should take care of that. 我得出的结论是,如果我要异步处理事件,则处理程序应注意这一点。

This isn't a hard and fast rule. 这不是一个硬性规定。 Not by any means. 绝不是。 For example, System.Timers.Timer raises the event on a ThreadPool thread by default, but you can specify a SynchronizingObject so that it can synchronize with the UI thread. 例如,默认情况下, System.Timers.Timer在ThreadPool线程上引发事件,但是您可以指定SynchronizingObject以便它可以与UI线程同步。

If you decide to go with asynchronous events, then I suggest that you include a facility such as the Timer's SynchronizingObject so that UI clients can use your class without having to muck around with the complexities of UI thread synchronization. 如果您决定使用异步事件,那么我建议您包括一个诸如Timer的SynchronizingObject之类的工具,以便UI客户端可以使用您的类而不必担心UI线程同步的复杂性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM