简体   繁体   English

如何同时调用异步方法两次?

[英]How to call async method twice simultaneously?

Here is the thing. 这是东西。 I called async method with parameters. 我用参数调用了异步方法。 So if i had only one example of the class, that using this method it works fine. 因此,如果我只有该类的一个示例,则使用此方法可以正常工作。 But if I got 2 examples of my class and they both calls this async method, but with different parameters, results of one returns faster and rized handler of other example of class. 但是,如果我有2个类的示例,并且它们都调用此async方法,但参数不同,则其中一个的结果返回的速度更快,并且该类的另一个示例的处理程序更合理。

I show a little example: 我举一个例子:

public class ClassExample
{
   public ClassExample(int someParameter)
   {
      GetAsyncMethodCompleted += ClassExampleGetAsyncMethodCompleted;
      GetAsyncMethod(someParameter);
   }
   void ClassExampleGetAsyncMethodCompleted (object sender, Args e)
   {
      GetAsyncMethodCompleted -= ClassExampleGetAsyncMethodCompleted;
   }
}

So it's pretty obviously that this line 所以很明显,这条线

 GetAsyncMethodCompleted -= ClassExampleGetAsyncMethodCompleted;

executed at the wrong time in this case: 在这种情况下在错误的时间执行:

ClassExample(1);
ClassExample(2);

I really get why it's happening. 我真的知道为什么会这样。 So I need to get how can I make it works in the most elegant way. 因此,我需要了解如何使其以最优雅的方式工作。

If you can change the class implementing async method then the most elegant way would be not to use Event-based asynchronous pattern. 如果可以更改实现异步方法的类,则最优雅的方法是不使用基于事件的异步模式。 If you can't change the class, but you are allowed to pass some user-state to the async method it could be used to find out if you should handle the event, eg: 如果您不能更改类,但是可以将某些用户状态传递给异步方法,则可以使用它来确定是否应该处理事件,例如:


public class ClassExample
{
   private object asyncCallToken = new object();

   public ClassExample(int someParameter)
   {
      GetAsyncMethodCompleted += ClassExampleGetAsyncMethodCompleted;
      GetAsyncMethod(someParameter, asyncCallToken);
   }
   void ClassExampleGetAsyncMethodCompleted (object sender, Args e)
   {
      if (e.UserState != asyncCallToken)
      {
          // the event was triggered by somebody's other call.
          return;
      }

      GetAsyncMethodCompleted -= ClassExampleGetAsyncMethodCompleted;
   }
}

Otherwise, I guess, there is no way to distinguish between events. 否则,我想没有办法区分事件。

If you can change your code, instead of using a shared event, use a delegate parameter. 如果可以更改代码,则可以使用委托参数,而不要使用共享事件。

public void AsyncExecute(int parameter, EventHandler completed)
{
    ...
}


//in your code

AsyncExecute(1, delegate (object sender, EventArgs e) { code for case 1... });
AsyncExecute(2, delegate (object sender, EventArgs e) { code for case 2... });

WARNING: Adding and removing delegates from events handlers is not thread safe. 警告:从事件处理程序中添加和删除委托不是线程安全的。 Since event handlers are linked lists, and since they are not exactly synchronized, adding and removing events from multiple threads can result in unexpected results. 由于事件处理程序是链接列表,并且由于它们未完全同步,因此从多个线程中添加和删除事件可能会导致意外结果。

To do that I usually use two static functions i wrote. 为此,我通常使用我编写的两个静态函数。 It is not useful in your case, that can be solved only saving somewhere the state of what delegate to call, but it can be useful in other cases: 它在您的情况下没有用,只能将某个调用的状态保存到某个地方才能解决,但在其他情况下可能有用:

public static class SPInterlocked
{
    public const int SpinWaitYieldThreshold = 10;

    /// <summary>
    /// Mantain a thread in wait state for a cycle.
    /// spinCounter must be a reference to a local integer variable initialized to zero.
    /// </summary>
    public static void SpinOnce(ref int spinCounter)
    {
        if (spinCounter > SpinWaitYieldThreshold || ProcessorCount <= 1)
        {
            int num = spinCounter >= SpinWaitYieldThreshold ? spinCounter - SpinWaitYieldThreshold : spinCounter;
            Thread.Sleep(num % 20 == 19 ? 1 : 0);
        }
        else
        {
            Thread.SpinWait(2 << spinCounter);
        }

        spinCounter = spinCounter == IntegerMaxValue ? SpinWaitYieldThreshold : spinCounter + 1;
    }

    /// <summary>Add an event handler as an atomic operation.</summary>
    /// <returns>True if value is not null; False if null.</returns>
    public static void AddHandler<EVENTHANDLER>(ref EVENTHANDLER handler, EVENTHANDLER value)
        where EVENTHANDLER : class
    {
        Delegate dvalue = value as Delegate;
        if (dvalue == null)
        {
            if (value == null)
                throw new ArgumentNullException("value");
            throw new ArgumentException("Specified value is not a delegate", "value");
        }

        EVENTHANDLER temp;
        EVENTHANDLER current = handler;
        for (int spinner = 0; ; )
        {
            temp = current;
            EVENTHANDLER combined = Delegate.Combine(temp as Delegate, dvalue) as EVENTHANDLER;
            current = Interlocked.CompareExchange(ref handler, combined, temp);
            if (current == temp)
                break;
            SpinOnce(ref spinner);
        }
        while (current != temp) ;
    }

    /// <summary>Remove an event handler as an atomic operation.</summary>
    /// <returns>True if operation was performed</returns>
    public static bool RemoveHandler<EVENTHANDLER>(ref EVENTHANDLER handler, EVENTHANDLER value)
        where EVENTHANDLER : class
    {
        Delegate dvalue = value as Delegate;
        if (dvalue != null)
        {
            EVENTHANDLER temp;
            EVENTHANDLER current = handler;
            for (int spinner = 0; ; )
            {
                temp = current;
                EVENTHANDLER combined = Delegate.Remove(temp as Delegate, dvalue) as EVENTHANDLER;
                current = Interlocked.CompareExchange(ref handler, combined, temp);
                if (current == temp)
                    break;
                SpinOnce(ref spinner);
            }
            return true;
        }
        return false;
    }
}

// Your code

public static class MyClass
{
    private EventHandler eMyEvent;

    public event EventHandler MyEvent
    {
        add { SPinterlocked<EventHandler>.AddHandler(ref this.eMyEvent, value); }
        remove { SPinterlocked<EventHandler>.RemoveHandler(ref this.eMyEvent, value); }
    }
}

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

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