- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在典型的 .NET 世界中,我们对大多数 I/O 操作使用基于事件的异步模式(事件处理程序),据我所知,更具体地说,引入了 I/O 完成端口以提高线程调度效率,像ThreadPool,因此我们不需要手动维护(初始化和销毁)线程来处理大量的I/O响应。
与此同时,我很自然地认为等待 I/O 响应不需要在现代 Windows 系统中因为硬件中断而阻塞任何线程,直到我在最近的项目中看到了一些 C++ 代码,甚至在 web 中看到了一些示例代码。
我没有任何 C++ 经验
第一段代码是关于串口监听的,伪C++代码(我输入的是C#风格)是这样的:
// loop checking the status
while(serialPort.Buffer.Count==0)
{
Thread.Sleep(100);
}
byte[] data = serialPort.Buffer;
// processing the actual data...
第二段代码是关于C++中I/O完成端口的使用:
while (::GetQueuedCompletionStatus(port,
&bytesCopied,
&completionKey,
&overlapped,
INFINITE))
{
if (0 == bytesCopied && 0 == completionKey && 0 == overlapped)
{
break;
}
else
{
// Process completion packet
}
}
很明显,他们都阻塞了线程。
所以我的问题是:
为什么那些代码没有选择基于事件的无线程阻塞方式?
如果.NET底层使用第二个示例的代码,那么在做I/O操作时实际上有线程被阻塞?
(可能有点跑题).NET I/O操作回调是否允许在之前的回调还在执行的时候并发重入?(根据我有限的测试,答案是否定的),为什么?
最佳答案
首先,阻塞本身并不是坏事。 Windows 应用程序中的“主”GUI 线程会触发其“OnClick”等事件,以响应从 Windows 消息队列(一个阻塞的生产者-消费者队列)接收到的消息。当没有收到消息时,线程阻塞在队列中。与大多数“非阻塞”基于 select() 的服务器一样 - select 是一个阻塞调用,(虽然它可以通过设置低/零超时来进行轮询 - 一个糟糕的设计)。
1) 异步设计本质上更复杂。每个套接字上下文数据(例如缓冲区)不能在基于堆栈的自动变量中维护,必须通过维护上下文对象的全局容器(必须由事件中的套接字句柄查找)来跨事件维护当它们被触发时),或者通过 I/O 请求发出上下文对象并从事件中的回调参数中检索它们。异步设计应该是完全异步的——如果可能的话,必须避免调用任何可能阻塞任何延长时间的东西。调用不透明的外部库、数据库查询等在这方面可能会很麻烦,阻塞假定的异步线程并阻止它响应事件。
第一个代码片段太可怕了,我很难为它找到任何理由。 sleep() 循环轮询在响应输入时具有内置的平均 50 毫秒延迟。当存在更好的同步和异步解决方案时,这只是 mega-lame。专用读取线程、排队的 APC、(完成例程)和 IOCP 都可用于串行端口。
第二个代码片段实际上是基于事件的异步。通过让处理程序线程使用完成消息返回的参数调用事件处理程序,您可以使它看起来更加“基于事件”。
IOCP 是 Windows 的首选高性能 I/O 系统。它可以处理许多类型的 I/O 操作,并且它基于线程池的处理程序可以承受偶尔的阻塞或冗长的操作,而不会阻止进一步 I/O 完成的处理。通过调用传递用户缓冲区允许驱动程序将它们直接加载到内核空间并删除一层复制。它不做的是避免在异步调用中维护上下文的需要。
每个客户端的同步线程通常用于可伸缩性要求被简单的内联代码淹没的情况,并且不受此类设计中固有的阻塞调用的影响。处理串行通信并不是可扩展到数千个端口的问题。
2) 当然,IOCP 处理程序线程在等待完成消息时阻塞。如果无事可做,线程应该阻塞:)
3) 他们应该这样做。添加一个额外的信号层以确保回调被串行处理涉及更多的开销,并将漏洞添加到回调中的任何类型的阻塞,阻止处理来自不需要阻塞的其他 IOCP 处理程序线程的其他回调.由于上下文作为参数传入,因此没有内在要求以串行方式运行 IOCP 驱动的回调。回调处理程序中的代码可以仅以状态机的方式对传递的信息进行操作。
也就是说,如果 MS .NET 确实提供了信号/队列来强制执行串行的、不可重入的回调,我不会感到惊讶。开发人员经验不足。经常在多线程回调中做他们不应该做的事情,例如。无需任何锁定即可访问全局/持久状态,或直接访问线程绑定(bind)的 GUI 控件。将调用序列化(通过将它们包装到 Windows 消息中或以其他方式)以牺牲性能为代价消除了这种风险。
关于c# - I/O 操作的 .NET 基于事件的异步模式是否会阻塞底层线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20944013/
对此感到疯狂,真的缺少一些东西。 我有webpack 4.6.0,webpack-cli ^ 2.1.2,所以是最新的。 在文档(https://webpack.js.org/concepts/mod
object Host "os.google.com" { import "windows" address = "linux.google.com" groups = ["linux"] } obj
每当我安装我的应用程序时,我都可以将数据库从 Assets 文件夹复制到 /data/data/packagename/databases/ .到此为止,应用程序工作得很好。 但 10 或 15 秒后
我在 cc 模式缓冲区中使用 hideshow.el 来折叠我不查看的文件部分。 如果能够在 XML 文档中做到这一点就好了。我使用 emacs 22.2.1 和内置的 sgml-mode 进行 xm
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
根据java: public Scanner useDelimiter(String pattern) Sets this scanner's delimiting pattern to a patt
我读过一些关于 PRG 模式以及它如何防止用户重新提交表单的文章。比如this post有一张不错的图: 我能理解为什么在收到 2xx 后用户刷新页面时不会发生表单提交。但我仍然想知道: (1) 如果
看看下面的图片,您可能会清楚地看到这一点。 那么如何在带有其他一些 View 的简单屏幕中实现没有任何弹出/对话框/模式的微调器日期选择器? 我在整个网络上进行了谷歌搜索,但没有找到与之相关的任何合适
我不知道该怎么做,我一直遇到问题。 以下是代码: rows = int(input()) for i in range(1,rows): for j in range(1,i+1):
我想为重写创建一个正则表达式。 将所有请求重写为 index.php(不需要匹配),它不是以/api 开头,或者不是以('.html',或'.js'或'.css'或'.png'结束) 我的例子还是这样
MVC模式代表 Model-View-Controller(模型-视图-控制器) 模式 MVC模式用于应用程序的分层开发 Model(模型) - 模型代表一个存取数据的对象或 JAVA PO
我想为组织模式创建一个 RDF 模式世界。您可能知道,组织模式文档基于层次结构大纲,其中标题是主要的分组实体。 * March auxiliary :PROPERTIES: :HLEVEL: 1 :E
我正在编写一个可以从文件中读取 JSON 数据的软件。该文件包含“person”——一个值为对象数组的对象。我打算使用 JSON 模式验证库来验证内容,而不是自己编写代码。符合代表以下数据的 JSON
假设我有 4 张 table 人 公司 团体 和 账单 现在bills/persons和bills/companys和bills/groups之间是多对多的关系。 我看到了 4 种可能的 sql 模式
假设您有这样的文档: doc1: id:1 text: ... references: Journal1, 2013, pag 123 references: Journal2, 2014,
我有这个架构。它检查评论,目前工作正常。 var schema = { id: '', type: 'object', additionalProperties: false, pro
这可能很简单,但有人可以解释为什么以下模式匹配不明智吗?它说其他规则,例如1, 0, _ 永远不会匹配。 let matchTest(n : int) = let ran = new Rand
我有以下选择序列作为 XML 模式的一部分。理想情况下,我想要一个序列: 来自 my:namespace 的元素必须严格解析。 来自任何其他命名空间的元素,不包括 ##targetNamespace和
我希望编写一个 json 模式来涵盖这个(简化的)示例 { "errorMessage": "", "nbRunningQueries": 0, "isError": Fals
首先,我是 f# 的新手,所以也许答案很明显,但我没有看到。所以我有一些带有 id 和值的元组。我知道我正在寻找的 id,我想从我传入的三个元组中选择正确的元组。我打算用两个 match 语句来做到这
我是一名优秀的程序员,十分优秀!