C# 异步/等待竞争条件

C# 异步/等待竞争条件,c#,asynchronous,stream,async-await,task-parallel-library,C#,Asynchronous,Stream,Async Await,Task Parallel Library,我相信我有下面的比赛条件。我正在手动构造一个HttpResponseMessage,其中JSON输出异步流。问题似乎出在柜台i上。我想在列表中第一次写入后的任何元素之前添加一个逗号 在列表的开头,有时我看到的第一个write3之后的前几条记录将没有前面的逗号。数字不一致,有时工作正常。我在本地机器上没有看到它,但在部署了更强大硬件的环境中,它是存在的 var LastUpdate = JsonConvert.SerializeObject(dt); var pre = $"{{ \"LastUp

我相信我有下面的比赛条件。我正在手动构造一个HttpResponseMessage,其中JSON输出异步流。问题似乎出在柜台i上。我想在列表中第一次写入后的任何元素之前添加一个逗号

在列表的开头,有时我看到的第一个write3之后的前几条记录将没有前面的逗号。数字不一致,有时工作正常。我在本地机器上没有看到它,但在部署了更强大硬件的环境中,它是存在的

var LastUpdate = JsonConvert.SerializeObject(dt);
var pre = $"{{ \"LastUpdate\": {LastUpdate}, \"List\":[";
var post = "]}";

HttpResponseMessage response = Request.CreateResponse();
response.Content = new PushStreamContent(
    async (stream, http, context) =>
    {
        try
        {
            int i = 0;
            var buffer = Encoding.UTF8.GetBytes(pre);
            await stream.WriteAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);

            var query = getQuery(id);                               
            await query
                .ForEachAsync(async entity =>
                {
                    var student = MapRecord(entity);
                    if (student != null)
                    {
                        var json = JsonConvert.SerializeObject(student);
                        buffer = Encoding.UTF8.GetBytes(((i > 0) ? ", " : "") + json);
                        await stream.WriteAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
                        i++;
                    }
                }, cancellationToken).ConfigureAwait(false);

            buffer = Encoding.UTF8.GetBytes(post);
            await stream.WriteAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
        }
如果你正在使用Thank@juharr,那么是的,你有一个比赛条件

该方法的签名为:

public static Task ForEachAsync<T>(
    this IQueryable<T> source,
    Action<T> action
)
如果你正在使用Thank@juharr,那么是的,你有一个比赛条件

该方法的签名为:

public static Task ForEachAsync<T>(
    this IQueryable<T> source,
    Action<T> action
)

如果您主要关心的是i计数器,那么可以使用联锁的.Increment来安全地执行Increment i。这将导致少量的同步性能争用,但您可以通过这种方式一致地更新i

例如:

Interlocked.Increment(ref i);

如果您主要关心的是i计数器,那么可以使用联锁的.Increment来安全地执行Increment i。这将导致少量的同步性能争用,但您可以通过这种方式一致地更新i

例如:

Interlocked.Increment(ref i);

ForEachAsync是如何声明的?@YuvalItzchakov可能是OP在使用ForEachAsync是如何声明的?@YuvalItzchakov可能是OP在使用ForEachAsync来防止数据库级别的阻塞此查询返回约100万行,是否有其他关于同步计数器的建议?如果是100万行,foreach可能不是最好的主意。是否有任何原因导致您实际手动执行序列化?如果这是不可避免的,我建议只使用同步委托并使用stream.Write而不是stream.WriteAsync。或者更好的方法是,为EF创建一个pull请求,并在ForEachAsync中添加一个调用异步委托的选项:引入整个结果集,映射和序列化内存异常命中。手动构造并不理想,但允许一次传输少量数据。使用这种方法,他们的资源占用非常少。也许更明智的想法是使用JsonTextWriter。请参阅问题。使用foreachasync防止数据库级阻塞此查询返回约100万行,是否还有其他关于同步计数器的建议?如果是100万行,foreach可能不是最好的主意。是否有任何原因导致您实际手动执行序列化?如果这是不可避免的,我建议只使用同步委托并使用stream.Write而不是stream.WriteAsync。或者更好的方法是,为EF创建一个pull请求,并在ForEachAsync中添加一个调用异步委托的选项:引入整个结果集,映射和序列化内存异常命中。手动构造并不理想,但允许一次传输少量数据。使用这种方法,他们的资源占用非常少。也许更明智的想法是使用JsonTextWriter。见问题。