2017-10-15 1 views
2

은 TPL에서 작업 구성과 스레드 로컬의 오용 된 사례에 대해 이야기하는 책에서 한 예를 이해할 수 없습니다.TPL에서 Task와 함께 C# ThreadLocal이 예상대로 작동하지 않는 이유는 무엇입니까?

예상 결과와 같이 10000이 아닌 이유는 무엇입니까?

누구든지 프로그램의 흐름에 대해 더 자세한 설명을 줄 수 있습니까? 아래의 프로그램 줄은 즉시 실행되고 일부 줄은 비동기 적으로 실행됩니까? 실행 순서와 순서?

using System; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Listing_05 { 

class BankAccount { 
    public int Balance { 
     get; 
     set; 
    } 
} 

class Listing_05 { 

    static void Main(string[] args) { 

     // create the bank account instance 
     BankAccount account = new BankAccount(); 

     // create an array of tasks 
     Task<int>[] tasks = new Task<int>[10]; 

     // create the thread local storage 
     ThreadLocal<int> tls = new ThreadLocal<int>(() => { 
      Console.WriteLine("Value factory called for value: {0}", 
       account.Balance); 
      return account.Balance; 
     }); 

     for (int i = 0; i < 10; i++) { 
      // create a new task 
      tasks[i] = new Task<int>(() => { 

       // enter a loop for 1000 balance updates 
       for (int j = 0; j < 1000; j++) { 
        // update the TLS balance 
        tls.Value++; 
       } 

       // return the updated balance 
       return tls.Value; 

      }); 

      // start the new task 
      tasks[i].Start(); 
     } 

     // get the result from each task and add it to 
     // the balance 
     for (int i = 0; i < 10; i++) { 
      //added by myself to see any hints but still cannot have insights 
      Console.WriteLine("task {0} results {1}", i, tasks[i].Result); 
      //end of my editing 

      account.Balance += tasks[i].Result; 
     } 

     // write out the counter value 
     Console.WriteLine("Expected value {0}, Balance: {1}", 
      10000, account.Balance); 

     // wait for input before exiting 
     Console.WriteLine("Press enter to finish"); 
     Console.ReadLine(); 
    } 
} 

} 8 개 코어 I7의 CPU를 사용하여 컴퓨터에서

결과, 8 개 스레드한다. 실행 여러 번 실행하면 여러 번 실행됩니다.

2nd execute

1st execute

는 프로그램이 작동하는 방법을 이해하고

+0

https://particular.net/blog/the-dangers-of-threadlocal을 참조하십시오. –

+0

예, 위의 질문을하기 전에 위의 링크에서 Google을했는데 어쩌면이 스레드 주제에 대해 초보자 일 수 있으므로 거의 이해할 수 없습니다. 왜 프로그램이 이런 식으로 행동하는지. 지금까지, 나의 이해는 ThreadLocal이 스레드에만있는 로컬 데이터라는 것입니다. 작업은 알 수없는 작업 스레드가 수행 할 작업을 설명하는 선언입니다. 스레드 로컬 초기화 데이터는 10 개의 태스크 중 일부가 10 개의 태스크 중 일부에서 이미 수정 된 동일한 스레드 데이터를 재사용하여 충돌하기 때문에 알 수 없습니다. 누군가가이 예제의 실행 방법을 설명 할 수 있습니까? 어떤 행은 실행을 연기해야합니까? – Cuda

+0

@Cuda, 가치 팩토리에는 두 개의'account.Balance'가 있습니다. 둘 다 다른 결과를 반환 할 자격이 있습니다. – PetSerAl

답변

2

작업이 동시에 코드를 실행하는 메커니즘을 제공하는이 방식으로 행동하지 마십시오. 그렇다고해서 반드시 별도의 스레드에서 실행될 필요는 없으며 재사용되지 않을 다중 스레드가 사용되는 경우에도 마찬가지입니다.

작업과 함께 스레드 로컬 저장소를 사용하지 마십시오.

대체 저장 옵션은 작업의 람다 함수 내에서 클로저를 사용하거나 클래스를 만들고 해당 클래스에 데이터를 저장 한 다음 해당 클래스의 메서드를 작업의 호출 수신자로 사용하는 것입니다. 나는 개인적으로 이것이 어쨌든 훨씬 더 깨끗하다고 ​​느낍니다.

한스 패스언트도 AsyncLocal에 대해 언급 할만한 가치가 있습니다. (필자는 직접 사용하지 않았기 때문에 주석을 달 수 없습니다).

+0

그래서 하나의 스레드가 동시에 작업을 수행 할 수 있거나 다중 스레드가 작업을 동시에 수행 할 수 있음을 의미합니다. 즉, 스레드 재사용에 대한 보장이 없으므로 단일 스레드에만 로컬 인 스레드 로컬 저장소를 사용하지 마십시오. 데이터 저장을위한 작업에는 무엇을 사용해야합니까? – Cuda

관련 문제