多线程同时异步

时间:2019-01-14 11:31:26

标签: c# multithreading asynchronous asp.net-web-api

我有以下代码:

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();

据我了解,这段代码将创建2个新线程,运行指定的方法,暂停主线程,直到两个线程都完成,然后继续执行。

假设我说的是正确的,到目前为止一切都很好。

接下来,我想尝试一下:

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();

基本上向每个线程添加异步并等待。

编译器接受此更改,并且似乎在本地运行,但是此代码还可以,并且是否有可能导致我进一步遇到任何问题,例如,线程会变得混乱,无法等待,混淆结果等

我对异步有相当好的理解,对多线程也有基本的了解,而且我无法想到为什么它不起作用。

代码在本地运行,但是我担心的是,在服务器上负载很重的情况下,可能会出现本地版本中不存在的问题。...

3 个答案:

答案 0 :(得分:2)

您的代码可以并行并且异步等待,只需一行:

await Task.WhenAll(_myService.GetMethod(variable1, variable2), _myService.GetMethod2(variable3, variable4)). 

这就是您所需要的。没有线程。没有加入。如果这些方法确实是I / O,则将没有线程。

与往常一样,必须阅读:https://blog.stephencleary.com/2013/11/there-is-no-thread.html

如果您的方法返回不同的结果并且需要分配给变量,则可以执行以下操作:

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

答案 1 :(得分:2)

  

编译器接受此更改,并且似乎在本地运行,但是此代码还可以,并且是否有可能导致我进一步遇到任何问题,例如,线程会变得混乱,无法等待,混淆结果等

     

我对异步有相当好的理解,对多线程也有基本的了解,而且我无法想到为什么它不起作用。

是的,这个代码将导致您的问题。像您期望的线程不等待。您正在将async void lambda传递给Thread构造函数,并且该线程在到达该lambda中的await之前,将退出 它设置object1 / object2变量。因此,这些变量完全有可能在null之后保留Join

在适当的解决方案,因为FCin posted,是使用异步并发性。 (I避免术语“平行”在这里,以减少与Parallel类型和任务并行库混乱)。异步并发使用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 :(得分:0)

您上面的代码没有利用线程,它阻塞了第一个线程,直到完成,然后启动了第二个

obj1Thread.Join();指示您的主线程等待obj1Thread退出后再继续。这意味着它将旋转obj1Thread然后等待它完成,这意味着:

  1. 创建线程1
  2. 运行线程1
  3. 退出线程1
  4. 创建线程2
  5. 运行线程2
  6. 退出线程2

您想这样做:

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();