如何同时调用async方法两次

本文关键字:两次 方法 何同时 调用 async | 更新日期: 2023-09-27 18:07:25

事情是这样的。我调用async方法与参数。如果我只有一个类的例子,使用这个方法就可以了。但如果我有两个类的例子,它们都调用了这个异步方法,但有不同的参数,一个的结果返回得更快,另一个类的例子的处理程序大小。

我举一个小例子:

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

很明显这一行

 GetAsyncMethodCompleted -= ClassExampleGetAsyncMethodCompleted;

在错误的时间执行:

ClassExample(1);
ClassExample(2);

我真的明白为什么会这样。所以我需要知道如何让它以最优雅的方式工作

如何同时调用async方法两次

如果你可以改变实现async方法的类,那么最优雅的方式就是不使用基于事件的异步模式。如果你不能改变类,但你可以将一些用户状态传递给async方法,它可以用来发现你是否应该处理事件,例如:

<>之前 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; } } 之前

如果你可以改变你的代码,而不是使用共享事件,使用委托参数。

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... });

警告:从事件处理程序中添加和删除委托不是线程安全的。由于事件处理程序是链表,并且它们不是完全同步的,因此在多个线程中添加和删除事件可能会导致意想不到的结果。

为了做到这一点,我通常使用我编写的两个静态函数。这在你的情况下是没有用的,这可以通过保存委托调用的状态来解决,但它在其他情况下是有用的:
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); }
    }
}