【发布时间】:2021-05-24 19:27:23
【问题描述】:
我需要帮助来使我的方法异步:
这是一种方法,现在可以正常工作,但是如果我删除 GetAwaiter().GetResult() ,我不会得到值,并且我被告知 GetAwaiter().GetResult() 不是一个好习惯。所以我想知道,我将如何更改它以使其异步。如果我编写内部异步任务,我会从我的其他方法中得到错误,其中它被称为返回类型不正确。我该如何解决?
internal string GeneratePartitionKey( Dictionary<string, EntityProperty> arg)
{
var partitionKey = RunScript( PSScript, filter );
return partitionKey.GetAwaiter().GetResult();
}
public async Task<string> RunScript( string scriptContents, List<string> scriptParameters )
{string script = @"Get-ChildItem C:\ ";
using( PowerShell ps = PowerShell.Create() )
{
ps.AddScript( script );
var pipelineObjects = await ps.InvokeAsync().ConfigureAwait( false );
StringBuilder stringBuilder = new StringBuilder();
foreach( var item in pipelineObjects )
{
stringBuilder.AppendLine( item.BaseObject.ToString() );
}
return stringBuilder.ToString();
}
}
//我们从这里开始,将 GeneratePartitionKey 更改为 async 时发生错误
await csvCopy.UploadNonCsvData( rule.GeneratePartitionKey,rule.GenerateRowKey, unzipper, schemaFormat, true, csvSchema );
public async Task UploadNonCsvData( Func<Dictionary<string, EntityProperty>, string> genPartitionKey,
Func<Dictionary<string, EntityProperty>, string> genRowKey,
Stream lines, string format, bool upsert, IDataClassifier classifier )
{
var dataclass = classifier.Classes.Where( c => c.Format.Equals( format, StringComparison.OrdinalIgnoreCase ) ).FirstOrDefault();
await WriteToTable( lines, dataclass,
genPartitionKey,
genRowKey, upsert );
}
public async Task WriteToTable( Stream lines, DataClass dataclass,
Func<Dictionary<string, EntityProperty>, string> genPartitionKey,
Func<Dictionary<string, EntityProperty>, string> genRowKey, bool upsert )
{
const int BatchSize = 100;
if( HasPartitionAndRowKey( dataclass.TableSchema.Fields ) )
{
genPartitionKey = ( Dictionary<string, EntityProperty> props ) => props["PartitionKey"].StringValue;
genRowKey = ( Dictionary<string, EntityProperty> props ) => props["RowKey"].ToString();
}
var tableRecords = ReadCSV( lines, dataclass.TableSchema.Fields )
.Select( props => new DynamicTableEntity( genPartitionKey( props ), genRowKey( props ), string.Empty, props ) )
.ToList();
await BatchInsertIntoTableStorage( BatchSize, tableRecords, upsert );
}
private IEnumerable<Dictionary<string, EntityProperty>> ReadCSV( Stream source, IEnumerable<TableField> cols )
{
using( TextReader reader = new StreamReader( source, Encoding.UTF8 ) )
{....... while( csv.Read() )
{
yield return map.ToDictionary(
col => col.Name,
col => EntityProperty.CreateEntityPropertyFromObject( csv.GetField( col.Type, col.Index ) ) );
}
}
private async Task BatchInsertIntoTableStorage( int batchSize, List<Task<DynamicTableEntity>> tableEntries, bool upsert )
{
CloudStorageAccount storageAccount;
if( string.IsNullOrEmpty( _account ) && string.IsNullOrEmpty( _key ) )
{
storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
}
else
{
storageAccount = new CloudStorageAccount(
new Microsoft.Azure.Cosmos.Table.StorageCredentials( _account, _key ),
true );
}
var tableClient = storageAccount.CreateCloudTableClient();
var table = tableClient.GetTableReference( _table );
foreach( var tableEntryBatch in tableEntries.Batch( batchSize ) )
{
var batchOperation = new TableBatchOperation();
foreach( var tableEntry in tableEntryBatch )
batchOperation.Add( upsert ? TableOperation.InsertOrReplace((ITableEntity) tableEntry ) : TableOperation.Insert((ITableEntity) tableEntry ) );
await table.ExecuteBatchAsync( batchOperation );
}
}
}
【问题讨论】:
-
async/await上升到调用堆栈的顶部,理想情况下你应该允许它这样做,只在最顶层阻塞。 -
为了避免 Sync-over-Async 的整个问题(就是这样),您可以尝试创建
RunScript的非异步版本。但是,我并没有确定您正在使用的所有方法都有非异步版本。 -
理想情况下,您可以将签名更改为
internal async Task<string> GeneratePartitionKey,并将任何调用方法更改为异步等 -
@JohnathanBarclay “只在最顶层阻塞。” 为什么阻塞?最顶层应该是
async void类型的事件。哪个不应该阻止 -
@PeterB B 创建非异步版本的 RunScript 很容易,但我想将其设为异步
标签: c#