C\#다 중 스 레 드 프로 그래 밍 에서 비동기 다 중 스 레 드 의 실현 및 스 레 드 풀 의 사용 을 분석 합 니 다.
스 레 드 는 컴퓨터 하드웨어 의 기능 이 아니 라 운영 체제 가 제공 하 는 논리 적 기능 입 니 다.스 레 드 는 본질 적 으로 프로 세 스 에서 동시에 실행 되 는 코드 이기 때문에 스 레 드 는 운영 체제 가 CPU 자원 을 투입 하여 운행 하고 관리 해 야 합 니 다.
1.다 중 스 레 드:
여러 개의 처리 핸들 을 사용 하여 여러 작업 을 동시에 제어 처리 하 는 기술블 로 거들 의 이해 에 따 르 면 다 중 스 레 드 는 이 응용 프로그램의 메 인 스 레 드 가 다른 여러 스 레 드 를 임명 하여 필요 한 기능 을 완성 하도록 협조 하 는 것 이 고 메 인 스 레 드 와 협조 스 레 드 는 완전히 독립 적 으로 진행 된다.이렇게 말 하면 이해 하기 어 려 울 지 모 르 겠 지만,뒤에 천천히 사용 하면 서 더욱 상세 한 설명 이 있 을 것 이다.
2.다 중 스 레 드 사용:
(1)가장 간단 하고 원시 적 인 사용 방법:Thread oGetArgThread=new Thread(new ThreadStart()=>{});이러한 용법 은 대부분의 사람들 이 사용 한 적 이 있 을 것 입 니 다.매개 변 수 는 ThreadStart 형식의 의뢰 입 니 다.ThreadStart 를 정의 로 전환 하면 알 수 있 습 니 다:
public delegate void ThreadStart();
이것 은 인자 가 없고 값 을 되 돌려 주지 않 는 의뢰 입 니 다.그래서 그의 사용 은 다음 과 같다.
static void Main(string[] args)
{
Thread oGetArgThread = new Thread(new ThreadStart(Test));
oGetArgThread.IsBackground = true;
oGetArgThread.Start();
for (var i = 0; i < 1000000; i++)
{
Console.WriteLine(" " + i);
//Thread.Sleep(100);
}
}
private static void Test()
{
for (var i = 0; i < 1000000; i++)
{
Console.WriteLine(" " + i);
//Thread.Sleep(100);
}
}
。 :
static void Main(string[] args)
{
Thread oGetArgThread = new Thread(new System.Threading.ThreadStart(() =>
{
for (var i = 0; i < 1000000; i++)
{
Console.WriteLine(" " + i);
//Thread.Sleep(100);
}
}));
oGetArgThread.IsBackground = true;
oGetArgThread.Start();
이것 은 위의 의미 와 같다.얻 은 결 과 는 다음 과 같다.메 인 스 레 드 와 백 스테이지 스 레 드 가 서로 독립 되 어 있다 는 것 을 설명 한다.시스템 에서 자원 을 관리 하여 집행 하 다.
만약 그렇다면 누군가가 물 어 볼 것 이다.만약 내 가 다 중 스 레 드 실행 방법 이 필요 하 다 면 매개 변수 가 있 거나 반환 값 이 있 거나 매개 변수 가 있 고 반환 값 이 있 을 까?조급해 하지 마 세 요.new Thread()의 구조 함수 몇 개 를 보 겠 습 니 다.
public Thread(ParameterizedThreadStart start);
public Thread(ThreadStart start);
public Thread(ParameterizedThreadStart start, int maxStackSize);
public Thread(ThreadStart start, int maxStackSize);
정의 로 이동 하면 알 수 있 는 매개 변 수 는 두 가지 가 있 습 니 다.하 나 는 반환 값 이 없 는 의뢰 이 고 다른 하 나 는 반환 값 이 있 는 의뢰 입 니 다.매개 변수 에 대한 위탁 사용 방법:
static void Main(string[] args)
{
Thread oThread = new Thread(new ParameterizedThreadStart(Test2));
oThread.IsBackground = true;
oThread.Start(1000);
}
private static void Test2(object Count)
{
for (var i = 0; i < (int)Count; i++)
{
Console.WriteLine(" " + i);
//Thread.Sleep(100);
}
}
인삼 과 반환 값 이 있 는 의뢰 에 대해 서 는 new Thread()라 는 방식 을 사용 하 는 것 은 해결 방안 이 없 음 이 분명 합 니 다.사실 인삼 과 반환 값 이 있 는 의뢰 는 비동기 로 이 루어 질 수 있 습 니 다.
public delegate string MethodCaller(string name);//
MethodCaller mc = new MethodCaller(GetName);
string name = "my name";//
IAsyncResult result = mc.BeginInvoke(name,null, null);
string myname = mc.EndInvoke(result);//
public string GetName(string name) //
{
return name;
}
이런 방식 에 대해 몇 가지 더 말 할 만 한 것 은:①
Thread oGetArgThread = new Thread(new ThreadStart(Test));
oGetArgThread.Join();// , , ,
② 스 레 드 의 우선 순 위 는 Thread 대상 의 Priority 속성 을 통 해 설정 할 수 있 습 니 다.Priority 속성 은 매개 변수 에 대응 합 니 다.
public enum ThreadPriority
{
// :
// System.Threading.Thread 。
Lowest = 0,
//
// :
// System.Threading.Thread Normal , Lowest 。
BelowNormal = 1,
//
// :
// System.Threading.Thread AboveNormal , BelowNormal 。
// , Normal 。
Normal = 2,
//
// :
// System.Threading.Thread Highest , Normal 。
AboveNormal = 3,
//
// :
// System.Threading.Thread 。
Highest = 4,
}
0 에서 4 까지 우선 순 위 는 낮은 것 에서 높 은 것 으로 나 타 났 다.③ 여러 스 레 드 가 하나의 대상 이나 자원 을 동시에 사용 하 는 경우,즉 스 레 드 의 자원 공유 에 대해 데이터 가 문란 하지 않도록 보통.Net 비관 적 인 잠 금 lock 방식 으로 처리 합 니 다.
private static object oLock = new object();
private static void Test2(object Count)
{
lock (oLock)
{
for (var i = 0; i < (int)Count; i++)
{
Console.WriteLine(" " + i);
//Thread.Sleep(100);
}
}
}
(2)작업 방식 으로 다 중 스 레 드 사용:
이런 방식 은 일반적으로 어떤 업 무 를 순환 적 으로 처리 해 야 하고 처 리 된 결 과 를 얻어 야 하 는 데 쓰 인 다.사용 코드 는 다음 과 같 습 니 다:
List<Task> lstTaskBD = new List<Task>();
foreach (var bd in lstBoards)
{
var bdTmp = bd;//
var oTask = Task.Factory.StartNew(() =>
{
var strCpBdCmd = "rm -Rf " + bdTmp.Path + "/*;cp -R " + CombineFTPPaths(FTP_EMULATION_BD_ROOT,
"bd_correct") + "/* " + bdTmp.Path + "/";
oPlink.Run(bdTmp.EmulationServer.BigIP, bdTmp.EmulationServer.UserName, bdTmp.EmulationServer.Password,
strCpBdCmd);
Thread.Sleep(500);
});
lstTaskBD.Add(oTask);
}
Task.WaitAll(lstTaskBD.ToArray());//
이런 방식 을 사용 할 때 이 문장 을 주의해 야 한다.var bdTmp=bd;여 기 는 임시 변 수 를 사용 해 야 합 니 다.그렇지 않 으 면 여러 bd 대상 이 데 이 터 를 쉽게 연결 할 수 있 습 니 다.관심 있 으 면 디 버 깅 해 보 세 요.이런 방법 은 비교적 간단 하 니 더 이상 말 하지 않 겠 다.물론 Task 대상 의 용법 은 그 뿐만 아니 라 임무 의 스케줄 링 등 복잡 한 논리 도 다 루 고 있 을 것 이다.블 로 거들 은 이 물건 들 에 대한 이해 에 한계 가 있어 서 설명 하지 않 았 다.(3)비동기 조작의 본질
모든 프로그램 은 최종 적 으로 컴퓨터 하드웨어 에 의 해 실 행 될 것 이기 때문에 비동기 작업 의 본질 을 잘 이해 하기 위해 우 리 는 그의 하드웨어 기 초 를 알 필요 가 있다.컴퓨터 하드웨어 를 잘 아 는 친구 들 은 DMA 라 는 단어 가 낯 설 지 않 을 것 이다.하 드 디스크,시디롬 의 기술 규격 에 모두 DMA 의 모델 기준 이 명확 하 다.사실은 네트워크 카드,사 운 드 카드,그래 픽 카드 도 DMA 기능 이 있다.DMA 는 직접 메모리 접근 이라는 뜻 으로,DMA 기능 을 가 진 하드웨어 가 메모리 와 데이터 교환 을 할 때 CPU 자원 을 소모 하지 않 아 도 된다 는 것 이다.CPU 가 데이터 전송 을 시작 할 때 명령 을 보 내 면 하드웨어 는 스스로 메모리 와 데 이 터 를 교환 하기 시작 합 니 다.전송 이 끝 난 후에 하드웨어 는 중단 을 촉발 하여 작업 이 완료 되 었 음 을 알 립 니 다.CPU 시간 을 소모 하지 않 아 도 되 는 I/O 작업 은 바로 비동기 작업 의 하드웨어 기반 이다.따라서 DOS 와 같은 단일 프로 세 스(스 레 드 개념 없 음)시스템 에서 도 비동기 DMA 작업 을 할 수 있 습 니 다.
(4)비동기 조작의 장단 점
비동기 작업 은 별도의 스 레 드 부담 없 이 리 셋 방식 으로 처리 할 수 있 기 때문에 디자인 이 좋 은 상황 에서 처리 함 수 는 공유 변 수 를 사용 하지 않 아 도 된다(전혀 사용 하지 않 아 도 최소한 공유 변수의 수량 을 줄 일 수 있다).물론 비동기 조작 도 완벽 하지 않다.비동기 작업 의 복잡 도가 비교적 높 고 프로그램 은 주로 리 셋 방식 으로 처리 하 며 일반인 의 사고방식 과 차이 가 있 으 며 디 버 깅 하기 어렵다.
3.스 레 드 탱크 의 용법:
일반적으로 서버 의 성능 등 문 제 를 고려 하여 한 시간 동안 시스템 스 레 드 수량 이 일정한 범위 에 있 도록 확보 하기 때문에 스 레 드 탱크 의 개념 을 사용 해 야 한다.대략적인 용법 은 다음 과 같다.
public class CSpiderCtrl
{
//
static Semaphore semaphore;
public static void Run()
{
//1. SuperLCBB
var oClient = new ServiceReference_SuperLCBB.SOAServiceClient();
//2. new 255( , , )
semaphore = new Semaphore(250, 255);
CLogService.Instance.Debug(" ...");
_TestBedGo(oClient);
}
//
private static void _TestBedGo(ServiceReference_SuperLCBB.SOAServiceClient oClient)
{
List<string> lstExceptPDUs = new List<string>(){
"SUPERLABEXP"
};
var oTestBedRes = oClient.GetTestBedExceptSomePDU(lstExceptPDUs.ToArray(), true);
if (CKVRes.ERRCODE_SUCCESS != oTestBedRes.ErrCode)
{
CLogService.Instance.Error("xxx");
return;
}
var lstTestBed = oTestBedRes.ToDocumentsEx();
System.Threading.Tasks.Parallel.ForEach(lstTestBed, (oTestBed) =>
{
// 255 , 255
semaphore.WaitOne();
//CLogService.Instance.Info(" :" + oTestBed[TBLTestBed.PROP_NAME]);
//Thread.Sleep(2000);
var strTestBedName = oTestBed[TBLTestBed.PROP_NAME] as string;
var strSuperDevIP = oTestBed[TBLTestBed.PROP_SUPERDEVIP] as string;
var strTestBedGID = oTestBed[TBLTestBed.PROP_GID] as string;
var strPdu = oTestBed[TBLTestBed.PROP_PDUGID] as string;
Thread.Sleep(new Random().Next(1000, 5000));
var oGetRootDevicesByTestBedGIDRes = oClient.GetRootDevicesByTestBedGID(strTestBedGID);
CLogService.Instance.Debug(strPdu + "―― Name:" + strTestBedName + " ");
Stopwatch sp = new Stopwatch();
sp.Start();
if (oGetRootDevicesByTestBedGIDRes.ErrCode != CKVRes.ERRCODE_SUCCESS || oGetRootDevicesByTestBedGIDRes.Documents.Count < 2)
{
CLogService.Instance.Debug("shit -- 3 Name:" + strTestBedName + "2 0");
// , return ,
semaphore.Release();
return;
}
var strXML = oGetRootDevicesByTestBedGIDRes.Documents[0];
var strExeName = oGetRootDevicesByTestBedGIDRes.Documents[1];
//var strExeName = "RateSpider";
var oSuperDevClient = new SuperDevClient(CSuperDev.ENDPOINT, string.Format(CSuperDev.SuperDevURL, strSuperDevIP));
try
{
oSuperDevClient.IsOK();
}
catch (Exception)
{
CLogService.Instance.Error(" Name:" + strTestBedName + " , ");
semaphore.Release();
return;
}
//2.3.1. SuperDev.Server(SuperDevIP), Run(XML Exename)
var oRunExeRes = new CKVRes();
try
{
oRunExeRes = oSuperDevClient.RunExeEx(strExeName, false, new string[] { strXML });
}
catch
{
//CLogService.Instance.Debug(" Name:" + strTestBedName + " :" + ex.Message);
}
sp.Stop();
CLogService.Instance.Debug(strPdu + "―― Name:" + strTestBedName + " " + sp.Elapsed);
//
semaphore.Release();
});
}
}
주의:Semaphore 대상 의 수량 은 서버 의 성능 에 따라 설정 해 야 합 니 다.System.Threading.Tasks.Parallel.Foreach 라 는 방식 은 lstTestBed.Length 스 레 드 를 동시에 시작 하여 한 가지 일 을 하 는 것 을 의미 합 니 다.
foreach(var oTestbed in lstTestBed)
{
Thread oThread=new Thread(new ThreadStart({ ...}));
}
(4)다 중 스 레 드 에는 말 할 만 한 SpinWait 류 가 있 는데 자전 기반 대기 에 대한 지원 을 제공 합 니 다.즉,하나의 의뢰 를 반복 적 으로 수행 하 는 것 을 지원 하고 조건 을 만족 시 킬 줄 알 면 돌아 오 는 것 입 니 다.우 리 는 그것 의 용법 을 보 겠 습 니 다.
public static void SpinUntil(Func<bool> condition);
public static bool SpinUntil(Func<bool> condition, int millisecondsTimeout);
public static bool SpinUntil(Func<bool> condition, TimeSpan timeout);
이 방법 은 세 개의 구조 함수 가 있 는데,후 두 개 는 한 시간 동안 전송 되 어야 하 며,다시 정 해진 시간 내 에 돌아 오지 않 으 면 자동 으로 뛰 어 나 와 순환 을 방지 해 야 한 다 는 것 을 의미한다.
SpinWait.SpinUntil(() =>
{
bIsworking = m_oClient.isworking(new isworking()).result;
return bIsworking == false;
}, 600000);
// 10
if (bIsworking)
{
oRes.ErrCode = "false 10 , ";
return oRes;
}
4.다 중 스 레 드 의 장단 점다 중 스 레 드 의 장점 이 뚜렷 하고 스 레 드 의 처리 절 차 는 여전히 순서대로 실행 되 며 일반인 의 사고방식 에 부합 되 기 때문에 프로 그래 밍 이 간단 하 다.그러나 다 중 스 레 드 의 단점 도 뚜렷 하 다.스 레 드 의 사용(남용)은 시스템 에 문맥 전환 에 추가 적 인 부담 을 줄 수 있다.또한 스 레 드 간 의 공유 변 수 는 잠 금 이 생 길 수 있 습 니 다.
5.적용 범위
스 레 드 와 비동기 작업 각자 의 장단 점 을 이해 한 후에 우 리 는 스 레 드 와 비동기 의 합 리 적 인 용 도 를 연구 할 수 있다.나 는 I/O 작업 을 실행 해 야 할 때 스 레 드+동기 I/O 작업 을 사용 하 는 것 보다 비동기 작업 을 사용 하 는 것 이 더 적합 하 다 고 생각한다.I/O 작업 은 직접적인 파일,네트워크 의 읽 기와 쓰기 뿐만 아니 라 데이터베이스 작업,웹 서비스,HttpRequest 와.net Remoting 등 크로스 프로 세 스 호출 도 포함한다.
한편,스 레 드 의 적용 범 위 는 장시간 의 CPU 연산 이 필요 한 장소 이다.예 를 들 어 시간 이 오래 걸 리 는 그래 픽 처리 와 알고리즘 이 실 행 된 것 이다.그러나 스 레 드 프로 그래 밍 이 간단 하고 습관 에 맞 기 때문에 많은 친구 들 이 스 레 드 를 사용 하여 시간 이 오래 걸 리 는 I/O 작업 을 수행 합 니 다.이렇게 하면 소수의 병발 조작 만 있 을 때 도 우아 함 을 해치 지 않 고 대량의 병발 조작 을 처리 해 야 할 때 적합 하지 않다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
WebView2를 Visual Studio 2017 Express에서 사용할 수 있을 때까지Evergreen .Net Framework SDK 4.8 VisualStudio2017에서 NuGet을 사용하기 때문에 패키지 관리 방법을 packages.config 대신 PackageReference를 사용해야...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.