问题
I have the following code:
myObject object1 = null;
Thread obj1Thread = new Thread(() => { object1 = _myService.GetMethod(variable1, variable2); });
obj1Thread.Start();
obj1Thread.Join();
myObject object2 = null;
Thread obj2Thread = new Thread(() => { object2 = _myService.GetMethod2(variable3, variable4); });
obj2Thread.Start();
obj2Thread.Join();
As far as I understand, this code will create 2 new threads, run the specified methods, pause the main thread until both these threads complete, and then continue execution.
Assuming what I say is correct, all fine so far.
Next I want to try this:
myObject object1 = null;
Thread obj1Thread = new Thread(async () => { object1 = await _myService.GetMethod(variable1, variable2); });
obj1Thread.Start();
obj1Thread.Join();
myObject object2 = null;
Thread obj2Thread = new Thread(async () => { object2 = await _myService.GetMethod2(variable3, variable4); });
obj2Thread.Start();
obj2Thread.Join();
Basically adding async and await to each thread.
The compiler accepts this change and it seems to run locally, but is this code ok, and is it likely to cause me any problems further down the line, for example will the threads get confused, fail to wait, mix up results etc.
I have a reasonably good understanding of async and a basic understanding of multi threading, and I cannot think of any reason why this would not work.
The code runs locally, but my worry is that under heavy load on the server issues may appear that were not present in a local version....
回答1:
The compiler accepts this change and it seems to run locally, but is this code ok, and is it likely to cause me any problems further down the line, for example will the threads get confused, fail to wait, mix up results etc.
I have a reasonably good understanding of async and a basic understanding of multi threading, and I cannot think of any reason why this would not work.
Yes, this code will cause you problems. The threads are not waiting as you expect. You're passing an async void lambda to the Thread
constructor, and that thread will exit as soon as it hits the await
in that lambda, before it sets the object1
/object2
variable. So it's entirely possible those variables remain null
after the Join
.
The proper solution, as FCin posted, is to use asynchronous concurrency. (I avoid the term "parallel" here to reduce confusion with the Parallel
type and the Task Parallel Library). Asynchronous concurrency uses Task.WhenAll
:
// Start both methods concurrently
var task1 = _myService.GetMethod(variable1, variable2);
var task2 = _myService.GetMethod2(variable3, variable4);
// (Asynchronously) wait for them both to complete.
await Task.WhenAll(task1, task2);
// Retrieve results.
myObject object1 = await task1;
myObject object2 = await task2;
回答2:
Your code can be parallel and asynchronously awaited with a single line:
await Task.WhenAll(_myService.GetMethod(variable1, variable2), _myService.GetMethod2(variable3, variable4)).
That's all you need. No threads. No joining. If these methods are truely i/o, there will be no thread.
As always, must read: https://blog.stephencleary.com/2013/11/there-is-no-thread.html
If your methods return different results and need to be assigned to variables, then you can do this:
Task<int> task1 = _myService.GetMethod(variable1, variable2);
Task<string> task2 = _myService.GetMethod2(variable3, variable4);
// Both tasks started.
int a = await task1; // Wait for first task
string b = await task2; // If this already finished, it will just return the result
回答3:
Your above code doesn't take advantage of threading, it blocks the first thread until it finishes then starts the second
obj1Thread.Join();
instructs your main thread to wait until obj1Thread exits before continuing. This means it will spin up obj1Thread then wait for it to complete, meaning you will:
- create thread 1
- Run thread 1
- Exit thread 1
- create thread 2
- Run thread 2
- Exit thread 2
You want to do:
myObject object1 = null;
Thread obj1Thread = new Thread(async () => { object1 = await _myService.GetMethod(variable1, variable2); });
obj1Thread.Start();
myObject object2 = null;
Thread obj2Thread = new Thread(async () => { object2 = await _myService.GetMethod2(variable3, variable4); });
obj2Thread.Start();
obj1Thread.Join();
obj2Thread.Join();
来源:https://stackoverflow.com/questions/54180685/multi-thread-and-async-at-same-time