我发现了一些使用c#async/ awaitkeywords的异步编程的最佳实践(我是c#5.0的新手).
给出的建议之一是:
稳定性:了解同步上下文
...某些同步上下文是不可重入和单线程的.这意味着在给定时间内只能在上下文中执行一个工作单元.一个例子是Windows UI线程或ASP.NET请求上下文.在这些单线程同步上下文中,很容易使自己陷入僵局.如果从单线程上下文中生成任务,然后在上下文中等待该任务,则等待代码可能会阻止后台任务.
public ActionResult ActionAsync()
{
// DEADLOCK: this blocks on the async task
var data = GetDataAsync().Result;
return View(data);
}
private async Task<string> GetDataAsync()
{
// a very simple async method
var result = await MyWebService.GetDataAsync();
return result.ToString();
}
Run Code Online (Sandbox Code Playgroud)
如果我自己尝试剖析它,主线程会产生一个新线程MyWebService.GetDataAsync();,但由于主线程在那里等待,它等待结果GetDataAsync().Result.同时,说数据准备好了.为什么主线程不继续它的延续逻辑并从中返回字符串结果GetDataAsync()?
有人可以解释一下为什么上面的例子中存在死锁吗?我完全不知道问题是什么......
我最近在接受采访时提到了这个问题.
我回答说如果交错出错就会发生死锁,但是访问者坚持认为可以编写一个总是会陷入死锁的程序而不管交错.
我们可以写这样的程序吗?你能指点我这样的示例程序吗?
我们在Stack Overflow SQL Server 2005数据库中看到了一些有害但罕见的死锁条件.
我附上了探查器,使用这篇关于解决死锁问题的优秀文章设置了一个跟踪配置文件,并捕获了一堆示例.奇怪的是,死锁写入始终是相同的:
UPDATE [dbo].[Posts]
SET [AnswerCount] = @p1, [LastActivityDate] = @p2, [LastActivityUserId] = @p3
WHERE [Id] = @p0
Run Code Online (Sandbox Code Playgroud)
另一个死锁声明各不相同,但它通常是对posts表的一些简单,简单的读取.这个人总是在僵局中被杀死.这是一个例子
SELECT
[t0].[Id], [t0].[PostTypeId], [t0].[Score], [t0].[Views], [t0].[AnswerCount],
[t0].[AcceptedAnswerId], [t0].[IsLocked], [t0].[IsLockedEdit], [t0].[ParentId],
[t0].[CurrentRevisionId], [t0].[FirstRevisionId], [t0].[LockedReason],
[t0].[LastActivityDate], [t0].[LastActivityUserId]
FROM [dbo].[Posts] AS [t0]
WHERE [t0].[ParentId] = @p0
Run Code Online (Sandbox Code Playgroud)
要非常清楚,我们没有看到写/写死锁,而是读/写.
我们目前混合使用LINQ和参数化SQL查询.我们已添加with (nolock)到所有SQL查询中.这可能对一些人有所帮助.我们昨天修复了一个(非常)写得不好的徽章查询,每次运行时间超过20秒,每分钟运行一次.我希望这是一些锁定问题的根源!
不幸的是,我在大约2小时前遇到了另一个死锁错误.同样的症状,同样的罪魁祸首写.
真正奇怪的是,您在上面看到的锁定写入SQL语句是非常特定的代码路径的一部分.它仅在向问题添加新答案时执行 - 它使用新答案计数和最后日期/用户更新父问题.显然,这与我们正在进行的大量读取相比并不常见!据我所知,我们在应用程序的任何地方都没有进行大量的写操作.
我意识到NOLOCK是一个巨大的锤子,但我们在这里运行的大多数查询都不需要那么准确.如果您的用户个人资料已过期几秒,您会关心吗?
正如Scott Hanselman在这里讨论的那样,将NOLOCK与Linq一起使用有点困难.
我们正在调整使用的想法
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Run Code Online (Sandbox Code Playgroud)
在基本数据库上下文中,以便我们所有的LINQ查询都有此设置.没有它,我们必须在3-4行事务代码块中包装我们所做的每个LINQ调用(好吧,简单的读取,这是绝大多数),这很难看.
我想我有点沮丧的是,SQL 2005中的琐碎读取可能会使写入死锁.我可以看到写/写死锁是一个很大的问题,但 …
我遇到了一个奇怪的情况,在静态初始化程序中使用带有lambda的并行流看似永远没有CPU利用率.这是代码:
class Deadlock {
static {
IntStream.range(0, 10000).parallel().map(i -> i).count();
System.out.println("done");
}
public static void main(final String[] args) {}
}
Run Code Online (Sandbox Code Playgroud)
这似乎是此行为的最小再现测试用例.如果我:
代码立即完成.谁能解释这种行为?这是一个错误还是这个意图?
我正在使用OpenJDK版本1.8.0_66-internal.
如何lock在JavaScript中实现与C#相同的东西?
所以,要解释我在想什么简单的用例是:
用户点击按钮B. B提出onclick事件.如果B是在event-state事件等待B是在ready-state传播之前.如果B处于ready-state,B已锁定并设置为event-state,则事件将传播.事件的传播完成后,B设置为ready-state.
我可以看到如何通过添加和删除ready-state按钮中的类来完成与此相近的操作.但是,问题是用户可以连续两次单击按钮,而不是可以设置变量,因此在某些情况下锁定尝试将失败.
有谁知道如何实现一个不会在JavaScript中失败的锁?
我在调用StackExchange.Redis时遇到了死锁情况.
我不确切知道发生了什么,这是非常令人沮丧的,我希望任何有助于解决或解决此问题的输入.
万一你也有这个问题,不想读这一切; 我建议你将尝试设置
PreserveAsyncOrder到false.Run Code Online (Sandbox Code Playgroud)ConnectionMultiplexer connection = ...; connection.PreserveAsyncOrder = false;这样做可能会解决此Q&A所涉及的僵局,并且还可以提高性能.
await和Wait()/ Result).当应用程序/服务启动时,它会正常运行一段时间,然后突然(几乎)所有传入的请求都会停止运行,它们永远不会产生响应.所有这些请求都在等待Redis完成呼叫的死锁.
有趣的是,一旦发生死锁,对Redis的任何调用都将挂起,但前提是这些调用是来自传入的API请求,这些调用是在线程池上运行的.
我们还从低优先级后台线程调用Redis,这些调用即使在发生死锁后也会继续运行.
似乎只有在线程池线程上调用Redis时才会出现死锁.我不再认为这是因为这些调用是在线程池线程上进行的.相反,似乎任何异步Redis调用没有延续,或者同步安全延续,即使在发生死锁情况后也会继续工作.(见下面我认为发生的事情)
混合引起的死锁await和Task.Result(像我们一样同步异步).但是我们的代码在没有同步上下文的情况下运行,因此这里不适用,对吧?
是的,我们不应该这样做.但我们这样做了,我们将不得不继续这样做一段时间.需要迁移到异步世界的大量代码.
同样,我们没有同步上下文,所以这不应该导致死锁,对吧?
ConfigureAwait(false)在任何设置之前设置await对此没有影响.
异步命令和Task.WhenAny等待StackExchange.Redis之后的超时异常
这是线程劫持问题.目前的情况如何?这可能是问题吗?
来自Marc的回答:
...混合等待和等待不是一个好主意.除了死锁之外,这是"同步异步" - 一种反模式.
但他也说:
SE.Redis在内部绕过sync-context(库代码正常),所以它不应该有死锁
因此,根据我的理解,StackExchange.Redis应该与我们是否使用同步异步 …
我通过线程获得C++错误:
terminate called without an active exception
Aborted
Run Code Online (Sandbox Code Playgroud)
这是代码:
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
template<typename TYPE>
class blocking_stream
{
public:
blocking_stream(size_t max_buffer_size_)
: max_buffer_size(max_buffer_size_)
{
}
//PUSH data into the buffer
blocking_stream &operator<<(TYPE &other)
{
std::unique_lock<std::mutex> mtx_lock(mtx);
while(buffer.size()>=max_buffer_size)
stop_if_full.wait(mtx_lock);
buffer.push(std::move(other));
mtx_lock.unlock();
stop_if_empty.notify_one();
return *this;
}
//POP data out of the buffer
blocking_stream &operator>>(TYPE &other)
{
std::unique_lock<std::mutex> mtx_lock(mtx);
while(buffer.empty())
stop_if_empty.wait(mtx_lock);
other.swap(buffer.front());
buffer.pop();
mtx_lock.unlock();
stop_if_full.notify_one();
return *this;
}
private:
size_t max_buffer_size;
std::queue<TYPE> buffer;
std::mutex mtx;
std::condition_variable stop_if_empty,
stop_if_full;
bool …Run Code Online (Sandbox Code Playgroud) 我在数据库中工作,我通过数据加载器在原始表中加载数据.但今天数据加载器因未知原因而陷入困境.然后我从Windows任务管理器停止了数据加载器.但后来我再次尝试在原始表中加载数据,但发现它已锁定,我无法对其进行任何操作.我尝试重新启动SQL Server服务,但它没有解决.我没有权限杀死此服务器上的进程.
下面是SQL Server显示的消息.
执行Transact-SQL语句或批处理时发生异常.(Microsoft.SqlServer.ConnectionInfo)
课程地点:
在Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(字符串的SqlCommand,ExecutionTypes executionType)
在Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(StringCollection sqlCommands,ExecutionTypes executionType)
在Microsoft.SqlServer.Management.Smo.ExecutionManager.ExecuteNonQuery (StringCollection查询)
在Microsoft.SqlServer.Management.Smo.SqlSmoObject.ExecuteNonQuery(StringCollection查询,布尔includeDbContext)
在Microsoft.SqlServer.Management.Smo.NamedSmoObject.RenameImplWorker(字符串newName)将
在Microsoft.SqlServer.Management.Smo.NamedSmoObject. RenameImpl(String newName)===================================
超出锁定请求超时时间.参数@objname是不明确的,或者声明的@objtype(OBJECT)是错误的.(.Net SqlClient数据提供程序)
服务器名称:162.44.25.59错误号码:1222
严重性:16状态:56
过程:sp_rename行号:282
我的SQL Server版本是2008 R2.
我有一个在TransactionScope中运行的代码块,在这段代码中,我多次调用DB.选择,更新,创建和删除整个色域.当我执行删除操作时,我使用SqlCommand的扩展方法执行它,如果查询死锁,它将自动重新提交查询,因为此查询可能会遇到死锁.
我相信当遇到死锁并且函数尝试重新提交查询时会发生此问题.这是我收到的错误:
与当前连接关联的事务已完成但尚未处理.必须先处理事务,然后才能使用连接执行SQL语句.
这是执行查询的简单代码(下面的所有代码都在使用TransactionScope执行):
using (sqlCommand.Connection = new SqlConnection(ConnectionStrings.App))
{
sqlCommand.Connection.Open();
sqlCommand.ExecuteNonQueryWithDeadlockHandling();
}
Run Code Online (Sandbox Code Playgroud)
以下是重新提交死锁查询的扩展方法:
public static class SqlCommandExtender
{
private const int DEADLOCK_ERROR = 1205;
private const int MAXIMUM_DEADLOCK_RETRIES = 5;
private const int SLEEP_INCREMENT = 100;
public static void ExecuteNonQueryWithDeadlockHandling(this SqlCommand sqlCommand)
{
int count = 0;
SqlException deadlockException = null;
do
{
if (count > 0) Thread.Sleep(count * SLEEP_INCREMENT);
deadlockException = ExecuteNonQuery(sqlCommand);
count++;
}
while (deadlockException != null && count < MAXIMUM_DEADLOCK_RETRIES);
if (deadlockException != null) throw deadlockException; …Run Code Online (Sandbox Code Playgroud) 当Java应用程序挂起时,您甚至不知道导致这种情况的用例并想要调查,我理解线程转储可能很有用.
但是,我们如何从线程转储中轻松地获取有用的数据以找出问题所在?我一直在使用的服务器应用程序产生很长的线程转储,因为它是一个EJB体系结构,并且线程转储包含许多容器线程,我不确定我应该关注它们(即没有运行我的应用程序代码的线程) ,但JBoss的代码).
昨天我尝试了Thread Dump Analyzer工具.该工具肯定比在文本编辑器中查看原始线程转储更好,因为您可以过滤掉您不感兴趣的线程,查看线程列表,单击线程以查看其详细信息,比较线程转储以查找长时间运行的线程等.见下面的截图:

但仍有太多数据需要分析 - 近300个线程.我不知道有什么标准可以用来过滤掉所有我不感兴趣的JBoss线程.我不确定我是否应该查看当前处于"可运行"状态的线程,或者"等待条件"和"在Object.wait"中的线程也很重要.
您通常会遵循的方法和一般使用的工具是什么?
deadlock ×10
c# ×3
java ×3
sql-server ×3
locking ×2
ado.net ×1
async-await ×1
asynchronous ×1
c#-5.0 ×1
c++ ×1
c++11 ×1
concurrency ×1
database ×1
debugging ×1
events ×1
fork-join ×1
java-8 ×1
java-stream ×1
javascript ×1
thread-dump ×1