.net – 如何使用Join连接PLINQ现有的LINQ查询?

前端之家收集整理的这篇文章主要介绍了.net – 如何使用Join连接PLINQ现有的LINQ查询?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用LINQ来比较两个DataSet,以创建新的行并更新现有的.我注意到完整的比较持续约1.5小时,两个内核中只有一个内核正忙(任务管理器占用cpu的使用率为50-52%).我必须承认,我对并行LINQ是全新的,但我认为它可以显着提高性能.

所以我的问题是,如何和什么应该并行化?

这些是原始查询(缩写为必需):

'check for new data
Dim srcUnique = From row In src.Email_Total
                Select Ticket_ID = row.ticket_id,Interaction = row.interaction,ModifiedAt = row.modified_time

Dim destUnique = From row In dest.ContactDetail
                 Where row.ContactRow.fiContactType = emailContactType.idContactType
                 Select row.ContactRow.Ticket_ID,row.Interaction,row.ModifiedAt

'get all emails(contactdetails) that are in source but not in destination
Dim diffRows = srcUnique.Except(destUnique).ToList

'get all new emails(according to ticket_id) for calculating contact columns
Dim newRowsTickets = (From row In src.Email_Total
                     Join d In diffRows
                     On row.ticket_id Equals d.Ticket_ID _
                     And row.interaction Equals d.Interaction _
                     And row.modified_time Equals d.ModifiedAt
                     Group row By Ticket_ID = row.ticket_id Into NewTicketRows = Group).ToList

For Each ticket In newRowsTickets
     Dim contact = dest.Contact.FindByTicket_IDfiContactType(ticket.Ticket_ID,emailContactType.idContactType)
     If contact Is Nothing Then
          ' Create new Contact with many sub-queries on this ticket(omitted) ****'
          Dim newContact = Me.dest.Contact.NewContactRow
          dest.Contact.AddContactRow(newContact)
          contact = newContact
     Else
          ' Update Contact with many sub-queries on this ticket(omitted) '
     End If
     daContact.Update(dest.Contact)

     ' Add new ContactDetail-Rows from this Ticket(this is the counterpart of the src.Email_Total-Rows,details omitted) '
     For Each newRow In ticket.NewTicketRows
         Dim newContactDetail = dest.ContactDetail.NewContactDetailRow
         newContactDetail.ContactRow = contact
         dest.ContactDetail.AddContactDetailRow(newContactDetail)
     Next
     daContactDetails.Update(dest.ContactDetail)
Next

注意:daContact和daContactDetails是sqlDataAdapters,source和dest是DataSet,Contact和ContactDetail是DataTable,每个ContactDetail都属于一个Contact.

即使不是这两个核心都不会使用100%的cpu,我认为如果我并行化查询,那么它会显着提高性能,因为第二个核心几乎处于空闲状态.对于每一个都可能是一个优化的地方,因为票不相关.所以我假设我可以循环多个线程并创建/更新记录并行.但是如何使用PLINQ?

侧面注意:正如我在评论中提到的,性能不是我迄今为止的关键因素,因为服务器的唯一目的是同步MysqL数据库(在另一台服务器上)与MS sql Server(在同一台服务器上)作为这个Windows服务).它作为由另一个服务生成的报告的来源.但这些报告只能每天生成一次.但除此之外,我有兴趣学习PLINQ,因为我认为这可能是一个很好的锻炼.
仅当目标数据库为空并且必须创建所有记录时,才需要提到的1,5h.如果两个数据库几乎同步,这个方法只需要1分钟左右.在未来的表现将变得更加重要,因为电子邮件只是几种联系人类型之一(聊天通话将超过1mil.records).我认为我会反正需要某种(LINQ)数据分页.

如果不清楚,我会相应地更新我的答案.提前致谢.

编辑:这是我调查和尝试的结果:

问题:如何使用联接“PLINQ”现有的LINQ查询

Answer:请注意,一些LINQ运算符是二进制的,它们以两个IEnumerables为输入.加入是这样一个运算符的完美例子.在这些情况下,最左侧数据源的类型决定是使用LINQ还是PLINQ.因此,您只需要在第一个数据源上调用AsParallel,使您的查询并行运行:

IEnumerable<T> leftData = ...,rightData = ...;
var q = from x in leftData.AsParallel()
        join y in rightData on x.a == y.b
        select f(x,y);

但是如果我以下列方式更改查询(请注意AsParallel):

Dim newRowsTickets = (From row In src.Email_Total.AsParallel()
                                        Join d In diffRows
                                        On row.ticket_id Equals d.Ticket_ID _
                                        And row.interaction Equals d.Interaction _
                                        And row.modified_time Equals d.ModifiedAt
                                    Group row By Ticket_ID = row.ticket_id Into NewTicketRows = Group).ToList

编译器会抱怨我需要将AsParallel添加到正确的数据源.所以这似乎是一个VB.NET问题或缺乏文档(文章来自2007).我认为后者是因为(除了那个可推荐的)文章还说你需要手动添加System.Concurrency.dll,但实际上它是.NET 4.0 Framework和命名空间Sytem.Threading.Tasks的一部分.

我意识到我不会从并行获利.除了在顺序模式下查询足够快(即使两个集合中几乎相同的行数导致最大的比较数量,我得到的结果不到30秒).但是,为了完整起见,我会补充一下.

所以我决定并行化每个与LINQ-Queries一样简单的东西,你只需要在最后添加AsParallel().
但是我意识到我需要强制使用WithExecutionMode(ParallelExecutionMode.ForceParallelism)的并行性,否则.NET决定在此循环中只使用一个内核.我也想告诉.NET,我希望使用尽可能多的线程,但不要超过8:WithDegreeOfParallelism(8).

现在,两个内核都在同一时间工作,但cpu占用率仍然保持在54%.

所以这是PLINQ版本到目前为止

Dim diffRows = srcUnique.AsParallel.Except(destUnique.AsParallel).ToList

Dim newRowsTickets = (From row In src.Email_Total.AsParallel()
                        Join d In diffRows.AsParallel()
                        On row.ticket_id Equals d.Ticket_ID _
                        And row.interaction Equals d.Interaction _
                        And row.modified_time Equals d.ModifiedAt
                    Group row By Ticket_ID = row.ticket_id Into NewTicketRows = Group).ToList

For Each ticket In newRowsTickets.
                    AsParallel().
                      WithDegreeOfParallelism(8).
                       WithExecutionMode(ParallelExecutionMode.ForceParallelism)
    '  blah,blah ...  '

    'add new ContactDetails for this Ticket(only new rows)
    For Each newRow In ticket.NewTicketRows.
                                AsParallel().
                                    WithExecutionMode(ParallelExecutionMode.Default)
        ' blah,blah ... '
    Next
    daContactDetails.Update(dest.ContactDetail)
Next

不幸的是,与顺序模式相比,使用AsParallel没有任何性能优势:

对于每个与AsParallel(hh:mm:ss.mm):

09/29/2011 18:54:36: Contacts/ContactDetails created or modified. Duration: 01:21:34.40

没有:

09/29/2011 16:02:55: Contacts/ContactDetails created or modified. Duration: 01:21:24.50

有人可以解释一下这个结果吗?数据库的写入访问是否为每个负责类似的时间?

以下是推荐读物:

> http://msdn.microsoft.com/en-us/magazine/cc163329.aspx(不可更新)

> List of changes since above article

> Overview of videos/articles according this topic
> PDF: When To Use ParallelForEach Or PLINQ
> When PLINQ will speedup performance

解决方法

有3点值得进一步调查,

>不要使用.toList().我可能是错的,但我认为使用.ToList
这样就不允许编译器优化查询,如果
进一步优化是可能的.
>使用您自己的过滤操作来比较两者的数据
destionations.它可能会给你更好的表现.
看看是否可以使用LinqDataview提供更好的
性能.

我不认为你在插入时会获得PLinq的优势.查看this answer了解更多详情.

希望有帮助.如果您需要澄清以上任何一点,请咨询.

猜你在找的MsSQL相关文章