- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试从 ThreadPool
移动我的一些旧项目和独立 Thread
到 TPL Task
,因为它支持一些非常方便的特性,比如与 Task.ContinueWith
的延续。 (以及来自 C# 5 的 async\await
)、更好的取消、异常捕获等。我很想在我的项目中使用它们。但是我已经看到了潜在的问题,主要是同步问题。
我写了一些代码来显示生产者/消费者问题,使用经典的独立 Thread
:
class ThreadSynchronizationTest
{
private int CurrentNumber { get; set; }
private object Synchro { get; set; }
private Queue<int> WaitingNumbers { get; set; }
public void TestSynchronization()
{
Synchro = new object();
WaitingNumbers = new Queue<int>();
var producerThread = new Thread(RunProducer);
var consumerThread = new Thread(RunConsumer);
producerThread.Start();
consumerThread.Start();
producerThread.Join();
consumerThread.Join();
}
private int ProduceNumber()
{
CurrentNumber++;
// Long running method. Sleeping as an example
Thread.Sleep(100);
return CurrentNumber;
}
private void ConsumeNumber(int number)
{
Console.WriteLine(number);
// Long running method. Sleeping as an example
Thread.Sleep(100);
}
private void RunProducer()
{
while (true)
{
int producedNumber = ProduceNumber();
lock (Synchro)
{
WaitingNumbers.Enqueue(producedNumber);
// Notify consumer about a new number
Monitor.Pulse(Synchro);
}
}
}
private void RunConsumer()
{
while (true)
{
int numberToConsume;
lock (Synchro)
{
// Ensure we met out wait condition
while (WaitingNumbers.Count == 0)
{
// Wait for pulse
Monitor.Wait(Synchro);
}
numberToConsume = WaitingNumbers.Dequeue();
}
ConsumeNumber(numberToConsume);
}
}
}
ProduceNumber
生成一个递增的整数序列,而
ConsumeNumber
将它们写入
Console
.如果生产运行得更快,数字将排队等待稍后消费。如果消费运行得更快,则消费者将等到一个数字可用。所有同步都是使用
Monitor
完成的和
lock
(内部也是
Monitor
)。
new Thread().Start()
与
Task.Run()
:
Task
是一种抽象,它甚至不能保证代码将在单独的线程上运行。在我的例子中,如果生产者控制方法同步运行,无限循环将导致消费者甚至永远不会启动。根据MSDN,提供TaskCreationOptions.LongRunning
运行任务时的参数应该提示 TaskScheduler
适本地运行该方法,但是我没有找到任何方法来确保它确实如此。据说 TPL 足够聪明,可以按照程序员预期的方式运行任务,但这对我来说似乎有点神奇。而且我不喜欢编程中的魔法。 Task
不能保证在启动时在同一线程上恢复。如果是这样,在这种情况下,它会尝试释放不属于它的锁,而另一个线程永远持有该锁,从而导致死锁。我记得不久前 Eric Lippert 写道,这就是为什么 await
的原因。不允许在 lock
中堵塞。回到我的例子,我什至不确定如何解决这个问题。 Monitor
进行同步的经典方法。 ,
Mutex
或
Semaphore
甚至正确的方法来做 TPL 代码?也许我错过了我应该使用的东西?
最佳答案
您的问题突破了 Stack Overflow 的广泛性限制。从平原搬家 Thread
基于 Task
的东西的实现和其他 TPL 功能涉及多种考虑因素。单独来看,几乎可以肯定每个问题都在之前的 Stack Overflow 问答中得到了解决,总的来说,在单个 Stack Overflow 问答中需要充分和全面地解决太多的考虑因素。
因此,话虽如此,让我们来看看您在这里提出的具体问题。
- TPL Task is an abstraction, which does not even guarantee that the code will run on a separate thread. In my example, if the producer control method runs synchronously, the infinite loop will cause the consumer to never even start. According to MSDN, providing a
TaskCreationOptions.LongRunning
parameter when running the task should hint theTaskScheduler
to run the method appropriately, however I didn't find any way to ensure that it does. Supposedly TPL is smart enough to run tasks the way the programmer intended, but that just seems like a bit of magic to me. And I don't like magic in programming.
Task
对象本身不保证异步行为。例如,一个
async
返回
Task
的方法对象可以根本不包含异步操作,并且可以在返回一个已经完成的
Task
之前运行很长时间。目的。
Task.Run()
保证异步操作。是
documented as such :
Queues the specified work to run on the ThreadPool and returns a task or Task<TResult> handle for that work
Task
对象本身抽象了“ future ”或“ promise ”的概念(使用编程中的同义词),具体实现与线程池密切相关。如果使用得当,您可以放心进行异步操作。
- If I understand how this works correctly, a TPL Task is not guaranteed to resume on the same thread as it started. If it does, in this case it would try to release a lock it doesn't own while the other thread holds the lock forever, resulting in a deadlock. I remember a while ago Eric Lippert writing that it's the reason why await is not allowed in a lock block. Going back to my example, I'm not even sure how to go about solving this issue.
Monitor
是。但是
Semaphore
不是。这对您是否有用取决于您要实现的目标。例如,您可以使用使用
BlockingCollection<T>
的长时间运行的线程来实现生产者/消费者模式。 ,根本不需要调用任何显式同步对象。如果你确实想使用 TPL 技术,你可以使用
SemaphoreSlim
和它的
WaitAsync()
方法。
Also, this made me think, is using the classical approach of synchronizing via Monitor, Mutex or Semaphore even the right way to do TPL code? Perhaps I'm missing something that I should be using instead?
Thread
基于 TPL 的编程不仅仅是从一种构造到另一种构造的直接映射。在某些情况下,这样做效率低下,而在其他情况下,它根本行不通。
async
/
await
是线程同步的必要性要小得多。一般的想法是异步执行操作,线程之间的交互最少。数据仅在明确定义的点(即从完成的
Task
对象中检索)在线程之间流动,从而减少甚至消除了显式同步的需要。
关于c# - 如何使用 Monitor/Mutex/Semaphore 同步 TPL 任务?还是应该完全使用其他东西?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35142942/
这个fn是吗: function isplainobj ( obj ) { return Object.prototype.toString.call( obj ) === "[object
我尝试创建一个我没有经验的小 bash 脚本。我尝试做类似的事情: #!/bin/bash statut="na" if [ $proc = 0 ]; then statut = "close
我想重写 HighLine 的几个方法来自定义我的控制台,目前我的代码如下所示: cmd = ask("#{@prompt_label} #{@prompt_separator} ",
鉴于下面的 HTML,我尝试使用 jQuery 来匹配所有具有类“foo”的跨度的列表项,并且该跨度应包含文本“relevant”。 Some text relevant Some more
我拥有一个 5 美元 20GB SSD Digital Ocean Droplet,它几乎用完了 Docker 镜像和容器的空间。 有没有办法购买一个卷,将其连接到服务器并安全地将所有 Docker
我有这样的表: id name number result stuff stuff stuff stuff 我只想将 class = "red" 添加到
我需要计算两点之间的距离,但不是以常规方式。我需要知道“东西距离”+“南北距离”。我想这比常规的“乌鸦飞翔”计算更简单,但我仍然不知道如何做到这一点。 我想使用 MySQL 查询来执行此操作,并且最好
#include #include #include typedef struct dict_pair { void *key; void *value; struct dict_p
为什么当我尝试通过 将 char[] word 写入控制台时会发生这种奇怪的事情 Console.WriteLine(word); 我得到了一个正确的结果,但是当我写的时候 Console.Write
一个简单的例子: class C{} class B{ @Inject C c; void doSomething(){ System.out.println(c);
我想做某事,但不确定如何描述它。我有这门课 public class Company { private List _persons; private Person GetPersonByNa
我正在尝试实现我自己的 qDebug()样式调试输出流,这基本上是我目前所拥有的: struct debug { #if defined(DEBUG) template std::os
所以我正在为我的应用程序编写一个搜索功能,代码如下: - (void) selectObject: (NSString *)notes{ [axKnotes removeAllObjects]
我想在 Rust 中匹配一种复杂的继承式东西: struct Entity { pub kind: EntityKind, } pub enum EntityKind { Player
我是 SQL 新手。这没有返回任何结果...... SELECT media.id as mediaid, media.title as mediatitle, media.description
在微型 SDCard 上写入 Android things 图像并将该卡插入 Raspberry Pi 3 Model B 并打开电源,启动时显示“Auto config Please wait”然后
这是一个常见的但是文本出现在框的右侧,不是极右但几乎是这样 h3: ................................................ .................
#include #include #include #include #include int main(int argc, string argv[]) { if(argc >
所以我试图让一些东西相互堆叠。首先,查看工作链接会有所帮助,您会看到问题所在: http://brownbox.net.au/clients/matchlessphotography/ 现在我需要使用
我想在禁用 javascript 时在我的网站顶部显示一条消息(就像在 SO 上一样),但在谷歌浏览器上不起作用 最佳答案 看起来是这样。 您可以使用 javascript 隐藏“noscript”消
我是一名优秀的程序员,十分优秀!