我正在尝试根据某些事件更新数据库。每当A生成事件时,B就会执行数据库更新。我不断收到以下例外:
“在先前的异步操作完成之前,第二个操作在此上下文上开始。使用await
确保在此上下文上调用另一个方法之前,所有异步操作都已完成。不保证任何实例成员都是线程安全的。”
我了解该异常,但是我不知道它来自何处,以及它是否与使用EventHandler有关。
经过长时间搜索:
async/await
订阅了活动Task.WaitAll()
class A {
public event EventHandler<LogArgs> LogEvent;
public void WorkInA() {
.....
this.SendLogEvent();
.....
this.SendLogEvent();
.....
}
private void SendLogEvent() {
this.LogEvent(this, args);
}
}
class B {
private A a;
public async void Init() {
//Before: a.LogEvent += LogEventToDB;
a.LogEvent += async (s, e) => await LogEventToDB(s, e);
}
public void DoWork() {
.....
a.WorkInA();
.....
}
private async Task LogEventToDB(object sender, LogMessageEventArgs e) {
.....
await this.unitOfWork.SaveAsync();
.....
}
}
//Inside unitOfWork
public async Task SaveAsync()
{
await this.context.SaveChangesAsync();
}
我想知道导致此问题的原因以及是否有可能解决此问题。
答案 0 :(得分:0)
是的,您的问题是由于事件处理所致。更具体地说,这是由于goquery
造成的。下面的代码行中的两者都属于package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
func findHeader(d *goquery.Document) string {
header := d.Find("h1").Text()
return header
}
func main() {
// create from a string
data := `
<html>
<head>
<title>My document</title>
</head>
<body>
<h1>Header</h1>
</body>
</html>`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
fmt.Println(findHeader(doc))
}
陷阱:
async void
problems with async void
之一是调用代码无法知道它何时完成。
如果您真的想对日志消息使用事件(这对我来说似乎有点奇怪),那么您必须让事件只是将日志消息添加到队列中(同步),并有一个单独的“工人”来提取消息走出队列,然后将它们异步发送到数据库。