2

트랜잭션 범위를 사용하는 비동기 캐시 및 데이터베이스 업데이트는 다음과 같습니다. 내가 사용하고있는 Apache Ignite.Net 캐시가 지원하지 않기 때문에 v 4.5.1에 ​​도입 된 TransactionScopeAsyncFlowOption.Enabled을 사용할 수 없습니다. 나는 명시 적으로 거래를 완료 Synchronization Context Send 방법을 사용하여 다음 현재 Synchronization Context을 캡처하여 해결 방법을 찾는 시도,하지만 난 여전히 오류 Transaction scope must be disposed on same thread it was createdTransactionScopeAsyncFlowOption.Enabled가없는 비동기 TransactionScope 사용

Async Update을 달성 대해 이동하는 방법을 어떤 제안을 얻을로이 작동하지 않습니다. 아파치의 Ignite 지원에 의해 제안 중 하나가 같은 것을 사용하는 것입니다

Task.WhenAll(cacheUpdate, databaseUpdate).Wait()을하지만 블로그를 통해 검색의 공정한 금액 후 최선의 선택

public async Task Update() 
{ 
    // Capture Current Synchronization Context 
    var sc = SynchronizationContext.Current; 

    TransactionOptions tranOptions = new TransactionOptions(); 
    tranOptions.IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead; 


    using (var ts = new TransactionScope()) 
    { 
     // Do Cache Update Operation as Async 
     Task cacheUpdate = // Update Cache Async 

     // Do Database Update Operation as Async 
     Task databaseUpdate = // Update Database Async 

     await Task.WhenAll(cacheUpdate, databaseUpdate); 

       sc.Send(new SendOrPostCallback(
       o => 
       { 
        ts.Complete(); 
       }), sc);   
    } 
} 
+3

에서 실행되는 비동기 방법을 얻을 TransactionScopeAsyncFlowOption.Enabled 필요하지 않습니다. .NET 4.0에서 실행해야합니까? – Evk

+0

이것은 Java 프로세스와 통신하는 Apache Ignite.Net에서 공개하는 Cache Update Async 메소드를 사용하며이 옵션은이 옵션을 지원하지 않습니다. 이유에 대한 모든 내부 세부 정보를 알지 못합니다. –

+2

이 기능을 타사 구성 요소의 일부 명시 적 지원이 필요하다는 것을 모르고 있었습니까? – Evk

답변

1

의 그러므로없는 한 비동기 코드 동기화를 할 것이며, 기사에서 스티븐 투브 (Stephen Toub)의 다음 블로그가 정확히 같은 스레드에서 비동기 지속 방법을 구현하는 데 도움이 됨으로써 트랜잭션 범위 문제를 피할 수있었습니다. 지금은 당신이 TransactionScopeAsyncFlowOption.Enabled을 사용할 수없는 이유는 확실히하지 않았다 TransactionScope

https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/

void Main() 
{ 
    // Modified Async Scheduler for Continuations to work on Exactly same thread 
    // Required in the case same Thread is required for Task Continuation post await 
    Run(async() => await DemoAsync()); 

    "Main Complete".Dump(); 
} 

static async Task DemoAsync() 
{ 
    // Transcation Scope test (shall dispose 
    using (var ts = new TransactionScope()) 
    {    
     await Cache + Database Async update 
     ts.Complete(); 
     "Transaction Scope Complete".Dump(); 
    } 
} 

// Run Method to utilize the Single Thread Synchronization context, thus ensuring we can 
// Control the threads/Synchronization context post await, cotinuation run of specific set of threads 

public static void Run(Func<Task> func) 
{ 
    // Fetch Current Synchronization context 
    var prevCtx = SynchronizationContext.Current; 

    try 
    { 
     // Create SingleThreadSynchronizationContext 
     var syncCtx = new SingleThreadSynchronizationContext(); 

     // Set SingleThreadSynchronizationContext 
     SynchronizationContext.SetSynchronizationContext(syncCtx); 

     // Execute Func<Task> to fetch the task to be executed 
     var t = func(); 

     // On Continuation complete the SingleThreadSynchronizationContext 
     t.ContinueWith(
      delegate { syncCtx.Complete(); }, TaskScheduler.Default); 

     // Ensure that SingleThreadSynchronizationContext run on a single thread 
     // Execute a Task and its continuation on same thread 
     syncCtx.RunOnCurrentThread(); 

     // Fetch Result if any 
     t.GetAwaiter().GetResult(); 
    } 
    // Reset the Previous Synchronization Context 
    finally { SynchronizationContext.SetSynchronizationContext(prevCtx); } 
} 

// Overriden Synchronization context, using Blocking Collection Consumer/Producer model 
// Ensure that same Synchronization context/Thread/set of threads are maintained 
// In this case we main a single thread for continuation post await 

private sealed class SingleThreadSynchronizationContext : SynchronizationContext 
{ 
    // BlockingCollection Consumer Producer Model 
    private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> 
     m_queue = new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>(); 

    // Override Post, which is called during Async continuation 
    // Send is for Synchronous continuation 
    public override void Post(SendOrPostCallback d, object state) 
    { 
     m_queue.Add(
      new KeyValuePair<SendOrPostCallback, object>(d, state)); 
    } 

    // RunOnCurrentThread, does the job if fetching object from BlockingCollection and execute it 
    public void RunOnCurrentThread() 
    { 
     KeyValuePair<SendOrPostCallback, object> workItem; 
     while (m_queue.TryTake(out workItem, Timeout.Infinite)) 
      workItem.Key(workItem.Value); 
    } 

    // Compete the SynchronizationContext 
    public void Complete() { m_queue.CompleteAdding(); } 
}