Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 紧密循环-磁盘速度为100%,四核CPU使用率为25%,磁盘写入速度仅为15 MB_Multithreading_Performance_Eventstoredb - Fatal编程技术网

Multithreading 紧密循环-磁盘速度为100%,四核CPU使用率为25%,磁盘写入速度仅为15 MB

Multithreading 紧密循环-磁盘速度为100%,四核CPU使用率为25%,磁盘写入速度仅为15 MB,multithreading,performance,eventstoredb,Multithreading,Performance,Eventstoredb,我有一个紧密的循环,它通过一堆Cart运行,Cart本身包含大约10个events事件对象,并通过一个中间存储库(jOliver common domain与GetEventStore.com重新连接)将它们以JSON格式写入磁盘: //创建约200000个购物车,每个购物车有约5个事件 List testData=testData.GenerateFrom(产品); foreach(testData中的var cart) { count=count+(购物车作为IAggregate).GetU

我有一个紧密的循环,它通过一堆Cart运行,Cart本身包含大约10个events事件对象,并通过一个中间存储库(jOliver common domain与GetEventStore.com重新连接)将它们以JSON格式写入磁盘:

//创建约200000个购物车,每个购物车有约5个事件
List testData=testData.GenerateFrom(产品);
foreach(testData中的var cart)
{
count=count+(购物车作为IAggregate).GetUncommittedEvents().count;
保存(购物车);
}
我看到磁盘上说它是100%,但吞吐量“低”(15MB/秒,每秒约5000个事件)。为什么会这样,我能想到的是:

  • 由于这是单线程的,那么25%的CPU使用率实际上是否意味着我所使用的1个内核的100%(以任何方式显示我的应用程序在Visual Studio中运行的特定内核)

  • 我是受i/O约束还是受CPU约束?如果我为每个CPU创建自己的线程池,我能期望更好的性能吗

  • 为什么我可以以大约120MB/秒的速度复制文件,但在我的应用程序中只能获得15MB/秒的吞吐量?这是由于许多较小数据包的写入大小造成的吗

  • 还有什么我错过的吗

    我使用的代码来自geteventstore文档/博客:

    public class GetEventStoreRepository : IRepository
    {
        private const string EventClrTypeHeader = "EventClrTypeName";
        private const string AggregateClrTypeHeader = "AggregateClrTypeName";
        private const string CommitIdHeader = "CommitId";
        private const int WritePageSize = 500;
        private const int ReadPageSize = 500;
    
        IStreamNamingConvention streamNamingConvention;
    
        private readonly IEventStoreConnection connection;
        private static readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None };
    
    
        public GetEventStoreRepository(IEventStoreConnection eventStoreConnection, IStreamNamingConvention namingConvention)
        {
            this.connection = eventStoreConnection;
            this.streamNamingConvention = namingConvention;
        }
    
        public void Save(IAggregate aggregate)
        {
            this.Save(aggregate, Guid.NewGuid(), d => { });
    
        }
    
        public void Save(IAggregate aggregate, Guid commitId, Action<IDictionary<string, object>> updateHeaders)
        {
            var commitHeaders = new Dictionary<string, object>
                    {
                        {CommitIdHeader, commitId},
                        {AggregateClrTypeHeader, aggregate.GetType().AssemblyQualifiedName}
                    };
            updateHeaders(commitHeaders);
    
            var streamName = this.streamNamingConvention.GetStreamName(aggregate.GetType(), aggregate.Identity);
            var newEvents = aggregate.GetUncommittedEvents().Cast<object>().ToList();
            var originalVersion = aggregate.Version - newEvents.Count;
            var expectedVersion = originalVersion == 0 ? ExpectedVersion.NoStream : originalVersion - 1;
            var eventsToSave = newEvents.Select(e => ToEventData(Guid.NewGuid(), e, commitHeaders)).ToList();
    
            if (eventsToSave.Count < WritePageSize)
            {
                this.connection.AppendToStreamAsync(streamName, expectedVersion, eventsToSave).Wait();
            }
            else
            {
                var startTransactionTask = this.connection.StartTransactionAsync(streamName, expectedVersion);
                startTransactionTask.Wait();
                var transaction = startTransactionTask.Result;
    
                var position = 0;
                while (position < eventsToSave.Count)
                {
                    var pageEvents = eventsToSave.Skip(position).Take(WritePageSize);
                    var writeTask = transaction.WriteAsync(pageEvents);
                    writeTask.Wait();
                    position += WritePageSize;
                }
    
                var commitTask = transaction.CommitAsync();
                commitTask.Wait();
            }
    
            aggregate.ClearUncommittedEvents();
        }
    
        private static EventData ToEventData(Guid eventId, object evnt, IDictionary<string, object> headers)
        {
            var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(evnt, serializerSettings));
    
            var eventHeaders = new Dictionary<string, object>(headers)
                    {
                        {
                            EventClrTypeHeader, evnt.GetType().AssemblyQualifiedName
                        }
                    };
            var metadata = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(eventHeaders, serializerSettings));
            var typeName = evnt.GetType().Name;
    
            return new EventData(eventId, typeName, true, data, metadata);
        }
    }
    
    公共类GetEventStoreRepository:IRepository { 私有常量字符串EventClrTypeHeader=“EventClrTypeName”; 私有常量字符串aggregateClTypeHeader=“aggregateClTypeName”; 私有常量字符串CommitId=“CommitId”; private const int WritePageSize=500; private const int ReadPageSize=500; IStreamNamingConvention streamNamingConvention; 私有只读IEventStoreConnection连接; 私有静态只读JsonSerializerSettings serializerSettings=new JsonSerializerSettings{TypeNameHandling=TypeNameHandling.None}; 公共GetEventStoreRepository(IEventStoreConnection eventStoreConnection,IStreamNamingConvention namingConvention) { this.connection=eventStoreConnection; this.streamNamingConvention=namingConvention; } 公共作废保存(IAggregate聚合) { Save(聚合,Guid.NewGuid(),d=>{}); } 公共void保存(IAggregate聚合、Guid提交、操作更新头) { var commitHeaders=新字典 { {commitId头,commitId}, {aggregateClTypeHeader,aggregate.GetType().AssemblyQualifiedName} }; 更新负责人(委员会负责人); var streamName=this.streamNamingConvention.GetStreamName(aggregate.GetType(),aggregate.Identity); var newEvents=aggregate.GetUncommittedEvents().Cast().ToList(); var originalVersion=aggregate.Version-newEvents.Count; var expectedVersion=originalVersion==0?expectedVersion.NoStream:originalVersion-1; var eventsToSave=newEvents.Select(e=>ToEventData(Guid.NewGuid(),e,committeaders)).ToList(); if(eventsToSave.Count评论中部分提到了这一点,但为了加强这一点,当您在所提到的代码中使用完全单线程时(尽管您使用异步,但您只是在等待它们,因此有效地使用同步),您正遭受上下文切换和EventStore协议来回切换的延迟和开销。要么真正走异步路线,但避免等待异步线程,而是将其并行化(EventStore喜欢并行化,因为它可以批处理多个写入),要么自己批处理,一次发送20个事件。

    如果没有实际将数据保存到磁盘的代码,我们就无话可说了。仔细检查您是否正确缓冲并使用了足够大的缓冲区。我不知道API,但您确实有一个
    CommitAsync
    并在代码中等待,如果您的事件不是几kb大,这听起来是一个非常糟糕的主意。您每秒提交数千次微小写入,这对于SSD来说是一个噩梦。这也是一场噩梦。对于您写入的大约每一百个字节,磁盘必须擦除一个512kB的页面,从旧扇区复制511kB,并附加您正在写入的几个字节。当您的程序消耗100%内核时,它不会被磁盘卡住。这也是磁盘写入速率低的原因之一。JSON并不是一种非常便宜的格式,它包含很多字符串。使用合适的探查器。删除WaitA
    public class GetEventStoreRepository : IRepository
    {
        private const string EventClrTypeHeader = "EventClrTypeName";
        private const string AggregateClrTypeHeader = "AggregateClrTypeName";
        private const string CommitIdHeader = "CommitId";
        private const int WritePageSize = 500;
        private const int ReadPageSize = 500;
    
        IStreamNamingConvention streamNamingConvention;
    
        private readonly IEventStoreConnection connection;
        private static readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None };
    
    
        public GetEventStoreRepository(IEventStoreConnection eventStoreConnection, IStreamNamingConvention namingConvention)
        {
            this.connection = eventStoreConnection;
            this.streamNamingConvention = namingConvention;
        }
    
        public void Save(IAggregate aggregate)
        {
            this.Save(aggregate, Guid.NewGuid(), d => { });
    
        }
    
        public void Save(IAggregate aggregate, Guid commitId, Action<IDictionary<string, object>> updateHeaders)
        {
            var commitHeaders = new Dictionary<string, object>
                    {
                        {CommitIdHeader, commitId},
                        {AggregateClrTypeHeader, aggregate.GetType().AssemblyQualifiedName}
                    };
            updateHeaders(commitHeaders);
    
            var streamName = this.streamNamingConvention.GetStreamName(aggregate.GetType(), aggregate.Identity);
            var newEvents = aggregate.GetUncommittedEvents().Cast<object>().ToList();
            var originalVersion = aggregate.Version - newEvents.Count;
            var expectedVersion = originalVersion == 0 ? ExpectedVersion.NoStream : originalVersion - 1;
            var eventsToSave = newEvents.Select(e => ToEventData(Guid.NewGuid(), e, commitHeaders)).ToList();
    
            if (eventsToSave.Count < WritePageSize)
            {
                this.connection.AppendToStreamAsync(streamName, expectedVersion, eventsToSave).Wait();
            }
            else
            {
                var startTransactionTask = this.connection.StartTransactionAsync(streamName, expectedVersion);
                startTransactionTask.Wait();
                var transaction = startTransactionTask.Result;
    
                var position = 0;
                while (position < eventsToSave.Count)
                {
                    var pageEvents = eventsToSave.Skip(position).Take(WritePageSize);
                    var writeTask = transaction.WriteAsync(pageEvents);
                    writeTask.Wait();
                    position += WritePageSize;
                }
    
                var commitTask = transaction.CommitAsync();
                commitTask.Wait();
            }
    
            aggregate.ClearUncommittedEvents();
        }
    
        private static EventData ToEventData(Guid eventId, object evnt, IDictionary<string, object> headers)
        {
            var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(evnt, serializerSettings));
    
            var eventHeaders = new Dictionary<string, object>(headers)
                    {
                        {
                            EventClrTypeHeader, evnt.GetType().AssemblyQualifiedName
                        }
                    };
            var metadata = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(eventHeaders, serializerSettings));
            var typeName = evnt.GetType().Name;
    
            return new EventData(eventId, typeName, true, data, metadata);
        }
    }