스레드 안전 사용을위한 정적 클래스의 범위를 제한하기 위해 AppDomain을 사용하는 방법은 무엇입니까?
-
08-07-2019 - |
문제
나는 제대로 건축되지 않은 솔루션에 물렸다. 스레드 안전하지 않습니다!
솔루션에 몇 가지 공유 클래스와 회원이 있으며 개발 중에 모든 것이 시원했습니다 ...
Biztalk는 내 전투선을 가라 앉았습니다.
우리는 내 어셈블리를 호출하기 위해 맞춤형 biztalk 어댑터를 사용하고 있습니다. 어댑터는 내 코드를 호출하고 병렬로 실행 중이므로 동일한 appDomain에서 여러 스레드를 사용하고 있다고 가정합니다.
내가하고 싶은 것은 내 코드를 자체 appdomain에서 실행하여 공유 된 문제가 서로 뭉개지 않을 것입니다.
Biztalk 어댑터가 Process () 메소드를 실행하는 매우 간단한 클래스가 있습니다.
내 프로세스 () 메소드 내에서 새로운 appdomain을 만들고 싶습니다. 그래서 Biztalk가 다른 스레드를 회전 할 때마다 고유 한 버전의 정적 클래스 및 메소드가 있습니다.
Biztalkadapter 코드 :
// this is inside the BizTalkAdapter and it is calling the Loader class //
private void SendMessage(IBaseMessage message, TransactionalTransmitProperties properties)
{
Stream strm = message.BodyPart.GetOriginalDataStream();
string connectionString = properties.ConnectionString;
string msgFileName = message.Context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties") as string;
Loader loader = new Loader(strm, msgFileName, connectionString);
loader.Process();
EventLog.WriteEntry("Loader", "Successfully processed: " + msgFileName);
}
이것은 클래스 비즈 토크 호출입니다.
public class Loader
{
private string connectionString;
private string fileName;
private Stream stream;
private DataFile dataFile;
public Loader(Stream stream, string fileName, string connectionString)
{
this.connectionString = connectionString;
this.fileName = fileName;
this.stream = stream;
}
public void Process()
{
//***** Create AppDomain HERE *****
// run following code entirely under that domain
dataFile = new DataFile(aredStream, fileName, connectionString);
dataFile.ParseFile();
dataFile.Save();
// get rid of the AppDomain here...
}
}
참고 : 로더 클래스는 DataFile 클래스에서 별도의 DLL에 있습니다.
모든 도움이 감사하겠습니다. 나는 코드 스레드-안전을 위해 계속 노력할 것이지만, 이것이 "간단한"대답 일 수 있다고 생각합니다.
누군가 다른 생각이 있으면 던져주세요.
고맙습니다,
키이스
완전성을 위해.
"Transport Advanced Options"대화 상자에서 Send 어댑터를 "주문 배달"으로 표시하면 내가 가진 멀티 스레드 문제를 피할 수 있다는 것을 알았습니다.
나는 이것이 내 문제에 대한 또 다른 가능한 대답이라고 생각하지만 반드시 질문에 대한 것은 아닙니다.
해결책
앱 도메인을 사용하면 다음과 같은 작업을 수행 할 수 있습니다.
public class Loader
{
private string connectionString;
private string fileName;
private Stream stream;
private DataFile dataFile;
public Loader(Stream stream, string fileName, string connectionString)
{
this.connectionString = connectionString;
this.fileName = fileName;
this.stream = stream;
}
public void Process()
{
//***** Create AppDomain HERE *****
string threadID = Thread.CurrentThread.ManagedThreadId.ToString();
AppDomain appDomain = AppDomain.CreateDomain(threadID);
DataFile dataFile =
(DataFile) appDomain.CreateInstanceAndUnwrap(
"<DataFile AssemblyName>",
"DataFile",
true,
BindingFlags.Default,
null,
new object[]
{
aredstream,
filename,
connectionString
},
null,
null,
null);
dataFile.ParseFile();
dataFile.Save();
appDomain.Unload(threadID);
}
}
다른 팁
스레드 안전 측면에서 정확히 어느 비트가 고통인지는 무엇입니까? 나는 정적 상태 나 싱글 톤을 볼 수 없으며, 적절한 "새로운"대상이있는 것 같습니다 ... 나는 눈이 멀었습니까?
그래서 당신이보고있는 증상은 무엇입니까 ...
AppDomain 답변은 (상대적으로) 느립니다. 미들웨어 지원 시스템의 일부로 이것은 괜찮을 수 있습니다 (즉, "상대적으로"는 같은 볼 파크에 있습니다).
만약 너라면 하다 어딘가에 정적 상태가 있는데, 때로는 작동하는 또 다른 옵션은 [Threadstatic]입니다. 런타임은 "이 정적 필드가 스레드 당 고유 한"것으로 해석합니다. 그러나 초기화에주의를 기울여야합니다. 스레드 A의 정적 생성자는 필드를 할당 할 수 있지만 스레드 B는 NULL/0/등을 볼 수 있습니다.
왜 순차적으로 실행하려는 코드를 잠그지 않겠습니까? 병목 현상이지만 멀티 스레드 환경에서 작동해야합니다.
public class Loader
{
private static object SyncRoot = new object();
private string connectionString;
private string fileName;
private Stream stream;
private DataFile dataFile;
public Loader(Stream stream, string fileName, string connectionString)
{
this.connectionString = connectionString;
this.fileName = fileName;
this.stream = stream;
}
public void Process()
{
lock(SyncRoot) {
dataFile = new DataFile(aredStream, fileName, connectionString);
dataFile.ParseFile();
dataFile.Save();
}
}
}
서로 충돌하는 정적을 공유 한 경우 [Threadstatic] 속성을 추가하려고 시도 할 수 있습니다. 이것은 각 스레드에 로컬로 만들 것입니다. 그것은 단기적으로 당신의 문제를 해결할 수 있습니다. 올바른 솔루션은 단순히 물건을 실로 삭제하기 위해 단순히 재구성하는 것입니다.
완전성을 위해.
"Transport Advanced Options"대화 상자에서 Send 어댑터를 "주문 배달"으로 표시하면 내가 가진 멀티 스레드 문제를 피할 수 있다는 것을 알았습니다.
나는 이것이 내 문제에 대한 또 다른 가능한 대답이라고 생각하지만 반드시 질문에 대한 것은 아닙니다.
각 통화마다 앱 도메인을 생성하고 찢어 버리는 것 - 나는 당신이 이것에 대한 성능에 대해 걱정하지 않습니까?
이상적으로는 호출 된 코드를 threadSafe로 변경해야합니다.