Azure编程笔记(5):长时间的异步操作带来的问题,azure异步




内容提要

Azure Storage里很多操作需要花费很长的时间。为了提高效率,这些耗时的操作是以异步的方式响应的。也就是说调用这些操作对应的函数虽然结束,但背后的操作可能还要持续一段时间。如果没有合理的对待从函数返回到操作真正结束这段时间,我们的程序就有可能出现问题。下面以删除CloudTable为例讨论这类问题。

问题描述

我们写一个简单的单元测试的Class来重现这个问题。首先我们定义两个函数,分别用来初始化测试函数和清理测试函数所留下的数据。函数InitializeTest初始化一个名叫TestTableCloudTable。如果该表不存在,则创建它。函数CleanupTest删除该表格。

private const string tableName = "TestTable";
private CloudTable table;
CloudTableClient tableClient;

[TestInitialize]
public void InitializeTest()
{
    string connectionString = Constant.connectionString;
    CloudStorageAccount storageAccount = Utilities.GetStorageAccount(connectionString);

    tableClient = storageAccount.CreateCloudTableClient();
    this.table = tableClient.GetTableReference(tableName);
    this.table.CreateIfNotExists();
}

[TestCleanup]
public void CleanupTest()
{
    if(table != null)
    {
        table.DeleteIfExists();
    }
}

为了使简化我们将要讨论的问题,我们添加两个看起来会永远通过的测试用例:

[TestMethod]
public void TestMethod1()
{
    Assert.IsTrue(true);
}

[TestMethod]
public void TestMethod2()
{
    Assert.IsTrue(true);
}

当我们在Visual Studio中运行上述两个测试用例时,却发现只有一个测试用例能够通过测试,另外一个测试用例则会抛出如下的异常:

问题根源

运行上述测试用例,第一个测试用例顺利完成,但在初始化第二个测试用例调用CreateIfNotExist试图创建CloudTable的时候出错了。从上面的异常信息的截图中我们可以看出,该异常的错误代码是TableBingDeleted

这个错误代码告诉我们的信息是,在清理第一个测试用例的数据时,调用DeleteIfExists删除CloudTable虽然顺利返回,但实际上删除操作并没有立即结束,只是在后台简单地设一个标签说该CloudTable需要被删除就返回了而已。真正删除一个CloudTable可能需要40秒甚至更多的时间。如果我们在DeleteIfExists结束之后立即调用CreateIfNotExist重新创建同一个CloudTable的时候,该表格实际上还存在并处在正被删除的状态,因此再次创建的操作无法完成。

解决问题

在本文的例子中,我们删除CloudTable仅仅是因为需要清理前一个测试遗留的数据。我们删除数据可以不删除整个CloudTable,而清除CloudTable里的所有数据。删除CloudTable里的数据(通过TableOperation.Delete)是同步的,如果函数返回,Azure会保证数据一定被删除。

如果我们一定要删除整个CloudTable,那么在创建CloudTable的时候就得做好错误处理。下面是一段调用CloudTable.CreateIfNotExists的参考代码:

[TestInitialize]
public void InitializeTest()
{
    string connectionString = Constant.connectionString;
    CloudStorageAccount storageAccount = Utilities.GetStorageAccount(connectionString);

    tableClient = storageAccount.CreateCloudTableClient();
    table = tableClient.GetTableReference(tableName);

    int retryTimes = 0;
    int maxRetryTimes = 20;
    StorageException lastException = null;

    while (retryTimes < maxRetryTimes)
    {
        try
        {
            table.CreateIfNotExists();
            break;
        }
        catch (StorageException excep)
        {
            var extendedInformation = excep.RequestInformation.ExtendedErrorInformation;
            var errorCode = extendedInformation.ErrorCode;
            if (errorCode == "TableBeingDeleted")
            {
                retryTimes++;
                lastException = excep;

                Thread.Sleep(5 * 1000); // Sleep 5 seconds
            }
            else
            {
                throw;
            }
        }
    }

    if(retryTimes == maxRetryTimes && lastException != null)
    {
        throw lastException;
    }
}

 


C# 网络编程 异步读写操作 怎实现

你这个范围大了
因为异步读写是 调用 异步线程帮我们操作的,这里面有 工作者线程与I/O线程

可以利用异步委托的方式,也可以利用new出来的线程来工作。

这只是思路。
 

c#中异步socket编程问题,回答完送50分

IAsyncResult 接口
表示异步操作的状态。

IAsyncResult 接口由包含可异步操作的方法的类实现。它是启动异步操作的方法的返回类型,如 FileStream.BeginRead,也是结束异步操作的方法的第三个参数的类型,如 FileStream.EndRead。当异步操作完成时,IAsyncResult 对象也将传递给由 AsyncCallback 委托调用的方法。

支持 IAsyncResult 接口的对象存储异步操作的状态信息,并提供同步对象以允许线程在操作完成时终止。

下面的示例说明如何使用 IAsyncResult 来获取异步操作的返回值。

// Asynchronous Callback method.
public static void MyCallback(IAsyncResult ar) {

// Obtains the last parameter of the delegate call.
int value = Convert.ToInt32(ar.AsyncState);

// Obtains return value from the delegate call using EndInvoke.
AsyncResult aResult = (AsyncResult)ar;
SampSyncSqrDelegate temp = (SampSyncSqrDelegate)aResult.AsyncDelegate;
int result = temp.EndInvoke(ar);

Console.Write("Simple.SomeMethod (AsyncCallback): Result of ");
Console.WriteLine("{0} in SampleSynchronized.Square is {1} ", value, result);
}
参考资料:msdn2.microsoft.com/...result(vs.80).aspx
 

相关内容