Task. 매개 변수로 실행 하시겠습니까?
저는 멀티 태스킹 네트워크 프로젝트를 진행하고 있으며 Threading.Tasks
. 나는 간단한 것을 구현했고 Task.Factory.StartNew()
어떻게 할 수 Task.Run()
있을까?
다음은 기본 코드입니다.
Task.Factory.StartNew(new Action<object>(
(x) =>
{
// Do something with 'x'
}), rawData);
개체 브라우저System.Threading.Tasks.Task
에서 살펴본 결과 유사한 매개 변수를 찾을 수 없습니다 . 매개 변수 를 취하는 것만 있고 유형 은 없습니다 .Action<T>
Action
void
단지 2 가지가있다는 비슷한 : static Task Run(Action action)
및 static Task Run(Func<Task> function)
수 있지만 모두 없습니다 포스트 매개 변수 (들).
예, 나는 그것을위한 간단한 확장 메서드를 만들 수 있습니다 알고 있지만 내 주요 질문은 우리가 한 줄에 쓸 수 있습니다 와 Task.Run()
?
private void RunAsync()
{
string param = "Hi";
Task.Run(() => MethodWithParameter(param));
}
private void MethodWithParameter(string param)
{
//Do stuff
}
편집하다
대중적인 요구로 인해 Task
시작된 것이 호출 스레드와 병렬로 실행 된다는 점에 유의해야합니다 . 기본값이라고 가정하면 TaskScheduler
.NET ThreadPool
. 어쨌든 이것은 전달되는 매개 변수 Task
가 잠재적으로 한 번에 여러 스레드에 의해 액세스되어 공유 상태가되는 것으로 간주 해야 함을 의미합니다 . 여기에는 호출 스레드에서 액세스하는 것이 포함됩니다.
위의 코드에서 그 경우는 완전히 논쟁의 여지가 있습니다. 문자열은 변경할 수 없습니다. 그것이 내가 그것들을 예로 사용한 이유입니다. 그러나 당신이 사용하지 않는다고 String
...
한 가지 해결책은 async
및 await
. 이것은 기본적으로 SynchronizationContext
호출 스레드의 를 캡처하고 호출 후 나머지 메서드에 대한 연속을 await
생성하고 생성 된 Task
. 이 메서드가 WinForms GUI 스레드에서 실행되는 경우 유형은 WindowsFormsSynchronizationContext
.
연속 작업은 캡처 된 항목에 다시 게시 된 후 실행 SynchronizationContext
됩니다. 기본적으로 만 다시 실행됩니다. 따라서 await
통화 후 시작한 스레드로 돌아갈 것 입니다. 를 사용하는 등 다양한 방법으로이를 변경할 수 있습니다 ConfigureAwait
. 즉, 그 방법의 나머지 부분까지 계속되지 않습니다 후 가 Task
다른 스레드에 완료했습니다. 그러나 호출 스레드는 나머지 메서드가 아닌 병렬로 계속 실행됩니다.
나머지 메소드 실행을 완료하기 위해 기다리는 것은 바람직 할 수도 있고 그렇지 않을 수도 있습니다. 나중에 해당 메서드에서에 전달 된 매개 변수에 액세스하는 것이 없으면 전혀 Task
사용하지 않을 수 있습니다 await
.
또는 나중에 메서드에서 이러한 매개 변수를 사용할 수도 있습니다. await
안전하게 일을 계속할 수 있으므로 즉시 할 이유가 없습니다 . Task
반환 된 값을 변수에 저장할 수 await
있고 나중에 같은 방법으로도 저장할 수 있습니다 . 예를 들어, 다른 작업을 한 후 전달 된 매개 변수에 안전하게 액세스해야하는 경우입니다. 다시 말하지만, 당신은 할 수 없습니다 필요 await
온 Task
당신이 그것을 실행하면 바로.
어쨌든 전달 된 매개 변수와 관련하여이 스레드를 안전하게 만드는 간단한 방법 Task.Run
은 다음과 같이하는 것입니다.
먼저 장식한다 RunAsync
과 async
:
private async void RunAsync()
중요 사항
링크 된 문서에서 언급했듯이 표시된 메서드는 void를 반환 하지 않는 것이 좋습니다 . 이에 대한 일반적인 예외는 버튼 클릭 등과 같은 이벤트 핸들러입니다. 그들은 무효를 반환해야합니다. 그렇지 않으면 난 항상 반환하려고 하거나 사용하는 경우 . 몇 가지 이유로 좋은 습관입니다.async
Task
Task<TResult>
async
이제 아래와 같이 await
실행할 수 Task
있습니다. await
없이는 사용할 수 없습니다 async
.
await Task.Run(() => MethodWithParameter(param));
//Code here and below in the same method will not run until AFTER the above task has completed in one fashion or another
따라서 일반적으로 await
작업을 수행하면 매개 변수에 전달 된 매개 변수를 한 번에 여러 스레드에서 수정하는 모든 함정과 함께 잠재적 인 공유 리소스로 취급하는 것을 피할 수 있습니다. 또한 폐쇄에 주의하십시오 . 나는 그것들을 깊이 다루지 않을 것이지만 링크 된 기사는 그것에 대해 훌륭한 일을한다.
사이드 노트
약간의 주제이지만 WinForms GUI 스레드에서으로 표시되어 있으므로 모든 유형의 "차단"을 사용하는 데주의하십시오 [STAThread]
. 사용 await
하면 전혀 차단되지 않지만 일종의 차단과 함께 사용되는 경우가 있습니다.
"Block"은 기술적으로 WinForms GUI 스레드를 차단할 수 없기 때문에 따옴표로 묶 입니다. 예, 당신이 사용하는 경우 lock
윈폼 GUI에이 스레드 합니다 아직도의 "차단"생각 당신에도 불구하고, 메시지를 펌프. 그렇지 않습니다.
이것은 매우 드문 경우에 기괴한 문제를 일으킬 수 있습니다. lock
예를 들어 그림을 그릴 때 를 사용하고 싶지 않은 이유 중 하나입니다 . 그러나 그것은 변덕스럽고 복잡한 경우입니다. 그러나 나는 그것이 미친 문제를 일으키는 것을 보았다. 그래서 완전성을 위해 기록했습니다.
변수 캡처를 사용하여 매개 변수를 "전달"합니다.
var x = rawData;
Task.Run(() =>
{
// Do something with 'x'
});
rawData
직접 사용할 수도 있지만 rawData
작업 외부의 값 (예 : for
루프 의 반복기 )을 변경하면 작업 내부의 값도 변경되므로주의해야합니다.
나는 이것이 오래된 스레드라는 것을 알고 있지만 수락 된 게시물에 여전히 문제가 있기 때문에 사용해야하는 솔루션을 공유하고 싶었습니다.
문제:
Alexandre Severino가 지적했듯이 param
(아래 함수에서) 함수 호출 직후에 변경되면에서 예기치 않은 동작이 발생할 수 있습니다 MethodWithParameter
.
Task.Run(() => MethodWithParameter(param));
내 솔루션 :
이를 설명하기 위해 다음과 같은 코드를 작성했습니다.
(new Func<T, Task>(async (p) => await Task.Run(() => MethodWithParam(p)))).Invoke(param);
이를 통해 작업을 시작한 후 매개 변수가 매우 빠르게 변경 되었음에도 불구하고 (게시 된 솔루션에 문제가 발생 함) 매개 변수를 비동기 적으로 안전하게 사용할 수있었습니다.
이 접근 방식을 사용하면 param
(값 유형)이 전달 된 값을 가져 오므로 param
변경 후 비동기 메서드가 실행 되더라도이 코드 줄이 실행되었을 때의 p
값 param
은 그대로 유지됩니다.
이제 다음을 수행 할 수도 있습니다.
Action<int> action = (o) => Thread.Sleep(o);
int param = 10;
await new TaskFactory().StartNew(action, param)
Just use Task.Run
var task = Task.Run(() =>
{
//this will already share scope with rawData, no need to use a placeholder
});
Or, if you would like to use it in a method and await the task later
public Task<T> SomethingAsync<T>()
{
var task = Task.Run(() =>
{
//presumably do something which takes a few ms here
//this will share scope with any passed parameters in the method
return default(T);
});
return task;
}
It's unclear if the original problem was the same problem I had: wanting to max CPU threads on computation inside a loop while preserving the iterator's value and keeping inline to avoid passing a ton of variables to a worker function.
for (int i = 0; i < 300; i++)
{
Task.Run(() => {
var x = ComputeStuff(datavector, i); // value of i was incorrect
var y = ComputeMoreStuff(x);
// ...
});
}
I got this to work by changing the outer iterator and localizing its value with a gate.
for (int ii = 0; ii < 300; ii++)
{
System.Threading.CountdownEvent handoff = new System.Threading.CountdownEvent(1);
Task.Run(() => {
int i = ii;
handoff.Signal();
var x = ComputeStuff(datavector, i);
var y = ComputeMoreStuff(x);
// ...
});
handoff.Wait();
}
참고URL : https://stackoverflow.com/questions/30225476/task-run-with-parameters
'Programing' 카테고리의 다른 글
Git 및 SSH, 어떤 키가 사용됩니까? (0) | 2020.11.08 |
---|---|
GIT_DISCOVERY_ACROSS_FILESYSTEM이 설정되지 않았습니다. (0) | 2020.11.08 |
백엔드에서 렌더링 된 매개 변수를 angular2 부트 스트랩 메서드로 전달하는 방법 (0) | 2020.11.08 |
UI 디스패처를 ViewModel에 전달하는 방법 (0) | 2020.11.08 |
HTML5는 폴더 또는 폴더 트리의 드래그 드롭 업로드를 허용합니까? (0) | 2020.11.08 |