C# 在实时项目中使用线程的最佳实践?
我试图在我的代码中使用线程,我在解决方案中使用了这段代码而没有使用线程。 我正在尝试在MS CRM中创建批量记录。有时,记录的数量会非常高C# 在实时项目中使用线程的最佳实践?,c#,multithreading,dynamics-crm,C#,Multithreading,Dynamics Crm,我试图在我的代码中使用线程,我在解决方案中使用了这段代码而没有使用线程。 我正在尝试在MS CRM中创建批量记录。有时,记录的数量会非常高 //Without Threading foreach (EntityCollection col in RetrieveContactsFromStaticML(ConnectToCrm(),marketingListRecord)) { CreateRecordsAgainstContact(_orgService, col, rewardDeta
//Without Threading
foreach (EntityCollection col in RetrieveContactsFromStaticML(ConnectToCrm(),marketingListRecord))
{
CreateRecordsAgainstContact(_orgService, col, rewardDetails, errorLoger);
}
但这需要花费太多的时间来执行。因为每次调用CreateRecordsAgainstContact方法时,进程都会等待该方法执行
所以我决定使用线程
//With Threading
foreach (EntityCollection col in RetrieveContactsFromStaticML(ConnectToCrm(),marketingListRecord))
{
var t1 = Task.Factory.StartNew(delegate ()
{
CreateRecordsAgainstContact(_orgService, col, rewardDetails,errorLoger);
});
}
但我不确定:这是使用线程的最佳方式吗
这是我的密码:
namespace ActivityDistribution
{
public class Distribution : IDistribution
{
private static IOrganizationService _orgService = null;
private static Logger errorLoger = new Logger();
public void CreateRewardsAndOfferRecords(Guid campaignActivityId)
{
RewardsAndOffers rewardDetails = new RewardsAndOffers();
Entity CampaignActivity = null;
Entity ParentCampaign = null;
EntityCollection marketingListCollection = null;
try
{
_orgService = ConnectToCrm();
#region RewardsAndOffers Details
CampaignActivity = _orgService.Retrieve("campaignactivity", campaignActivityId, new ColumnSet("subject", "regardingobjectid", "channeltypecode"));
ParentCampaign = _orgService.Retrieve("campaign", new Guid(((EntityReference)CampaignActivity["regardingobjectid"]).Id.ToString()), new ColumnSet("name", "istemplate", "statuscode", "new_rewardcategory", "new_rewardsubcategory"));
rewardDetails.CampaignActivity = new EntityReference(CampaignActivity.LogicalName, CampaignActivity.Id);
rewardDetails.ParentCampaign = new EntityReference(ParentCampaign.LogicalName, ParentCampaign.Id);
#endregion
#region Get MarketingList of given Campaign Activity
QueryExpression queryMarketingList = new QueryExpression("list")
{
ColumnSet = new ColumnSet("query", "listname", "type"),
LinkEntities =
{
new LinkEntity
{
JoinOperator = JoinOperator.Inner,
LinkFromAttributeName = "listid",
LinkFromEntityName = "list",
LinkToAttributeName = "itemid",
LinkToEntityName = "campaignactivityitem",
LinkEntities =
{
new LinkEntity
{
JoinOperator = JoinOperator.Inner,
LinkFromAttributeName = "campaignactivityid",
LinkFromEntityName = "campaignactivityitem",
LinkToAttributeName = "activityid",
LinkToEntityName = "campaignactivity",
LinkCriteria =
{
Conditions =
{
new ConditionExpression("activityid", ConditionOperator.Equal, rewardDetails.CampaignActivity.Id)
}
}
}
},
}
}
};
marketingListCollection = _orgService.RetrieveMultiple(queryMarketingList);
#endregion
#region Fetch MarketingList's Contacts and Create Rewards&Offers Redords against MarketingList's Contacts
if (marketingListCollection.Entities.Count() > 0)
foreach (var marketingListRecord in marketingListCollection.Entities)
{
//With Threading
foreach (EntityCollection col in RetrieveContactsFromStaticML(ConnectToCrm(), marketingListRecord))
{
var t1 = Task.Factory.StartNew(delegate ()
{
CreateRecordsAgainstContact(_orgService, col, rewardDetails, errorLoger);
});
}
//Without Threading
foreach (EntityCollection col in RetrieveContactsFromStaticML(ConnectToCrm(), marketingListRecord))
{
CreateRecordsAgainstContact(_orgService, col, rewardDetails, errorLoger);
}
}
#endregion
}
catch (Exception ex)
{
errorLoger.Log(ex);
}
}
private static IOrganizationService ConnectToCrm()
{
IOrganizationService orgService = null;
ClientCredentials credentials = new ClientCredentials();
credentials.UserName.UserName = Credentials.UserName;
credentials.UserName.Password = Credentials.Password;
Uri serviceUri = new Uri(Credentials.OrganizationService);
OrganizationServiceProxy proxy = new OrganizationServiceProxy(serviceUri, null, credentials, null);
proxy.EnableProxyTypes();
proxy.Timeout = new TimeSpan(4, 0, 0);
orgService = (IOrganizationService)proxy;
return orgService;
}
public static IEnumerable<EntityCollection> RetrieveContactsFromStaticML(IOrganizationService service, Entity entity)
{
var queryExpression = new QueryExpression()
{
Distinct = false,
EntityName = "contact",
ColumnSet = new ColumnSet("fullname", "telephone1"),
LinkEntities =
{
new LinkEntity
{
JoinOperator = JoinOperator.Inner,
LinkFromAttributeName = "contactid",
LinkFromEntityName = "contact",
LinkToAttributeName = "entityid",
LinkToEntityName = "listmember",
LinkEntities =
{
new LinkEntity
{
JoinOperator = JoinOperator.Inner,
LinkFromAttributeName = "listid",
LinkFromEntityName = "listmember",
LinkToAttributeName = "listid",
LinkToEntityName = "list",
LinkCriteria =
{
Conditions =
{
new ConditionExpression("listid", ConditionOperator.Equal, entity.Id)
}
}
}
}
}
}
};
foreach (EntityCollection col in RetrieveMultipleRecords(service, queryExpression))
{
yield return col;
}
}
public static IEnumerable<EntityCollection> RetrieveMultipleRecords(IOrganizationService service, QueryExpression queryExpression)
{
int fetchCount = 5000;
int pageNumber = 1;
queryExpression.PageInfo = new PagingInfo();
queryExpression.PageInfo.Count = fetchCount;
queryExpression.PageInfo.PageNumber = pageNumber;
queryExpression.PageInfo.PagingCookie = null;
while (true)
{
EntityCollection col = new EntityCollection();
EntityCollection collection = service.RetrieveMultiple(queryExpression);
if (collection.Entities.Count > 0)
foreach (Entity e in collection.Entities)
{
col.Entities.Add(e);
}
queryExpression.PageInfo.PageNumber++;
queryExpression.PageInfo.PagingCookie = collection.PagingCookie;
yield return col;
if (!collection.MoreRecords)
yield break;
}
}
public static void CreateRecordsAgainstContact(IOrganizationService service, EntityCollection contactColletion, RewardsAndOffers rewardsAndOffers, Logger errorLoggger)
{
var requestWithResults = new ExecuteMultipleRequest()
{
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = true,
ReturnResponses = false
},
Requests = new OrganizationRequestCollection()
};
int maxRecordExecuteCount = 0;
int totalRecords = 0;
foreach (Entity contact in contactColletion.Entities)
{
Entity entity = new Entity("new_rewardsandoffers");
entity["new_campaignactivity"] = rewardsAndOffers.CampaignActivity;
entity["new_campaign"] = rewardsAndOffers.ParentCampaign;
entity["new_contact"] = new EntityReference("contact", contact.Id);
CreateRequest createRequest = new CreateRequest { Target = entity };
requestWithResults.Requests.Add(createRequest);
maxRecordExecuteCount++;
totalRecords++;
if (maxRecordExecuteCount == 1000 || totalRecords == contactColletion.Entities.Count())
{
service.Execute(requestWithResults);
maxRecordExecuteCount = 0;
requestWithResults.Requests = new OrganizationRequestCollection();
}
}
}
}
public class RewardsAndOffers
{
public EntityReference ParentCampaign { get; set; }
public EntityReference CampaignActivity { get; set; }
public OptionSetValue RewardCategory { get; set; }
public OptionSetValue RewardSubCategory { get; set; }
}
class Credentials
{
public static string OrganizationService
{
get
{
return ConfigurationManager.AppSettings["OrganizationService"].ToString();
}
}
public static string UserName
{
get
{
return ConfigurationManager.AppSettings["UserName"].ToString();
}
}
public static string Password
{
get
{
return ConfigurationManager.AppSettings["Password"].ToString();
}
}
}
}
我想使用手动创建的线程并控制它的计数。在此示例中,有一个由多个线程处理的公共队列:
public class InsertBulkRecordsTask
{
private ConcurrentQueue<Contact> _contactsQueue;
public void Execute()
{
try
{
var contacts = RetrieveContactsFromStaticML(ConnectToCrm(), marketingListRecord);
_contactsQueue = new ConcurrentQueue<Contact>(contacts);
var threadsCount = AppConfigReader.ThreadsCount;
var threads = new List<Thread>();
for (int i = 0; i < threadsCount; i++)
threads.Add(new Thread(ProcessContactsQueue) { IsBackground = true });
threads.ForEach(r => r.Start());
threads.ForEach(r => r.Join());
}
catch (Exception ex)
{
// TODO: log
}
}
private void ProcessContactsQueue()
{
try
{
while (_contactsQueue.IsEmpty == false)
{
Contact contact;
if (_contactsQueue.TryDequeue(out contact) && contact != null)
{
try
{
// Save contact
}
catch (Exception ex)
{
// TODO: log
}
}
}
}
catch (Exception ex)
{
// TODO: log
}
}
}
ExecuteMultipleRequest用于批量操作,我建议将其签出并避免执行线程:
这是MSDN页面中提供的示例,它演示了多个创建请求:
// Get a reference to the organization service.
using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri, serverConfig.HomeRealmUri,serverConfig.Credentials, serverConfig.DeviceCredentials))
{
// Enable early-bound type support to add/update entity records required for this sample.
_serviceProxy.EnableProxyTypes();
#region Execute Multiple with Results
// Create an ExecuteMultipleRequest object.
requestWithResults = new ExecuteMultipleRequest()
{
// Assign settings that define execution behavior: continue on error, return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};
// Create several (local, in memory) entities in a collection.
EntityCollection input = GetCollectionOfEntitiesToCreate();
// Add a CreateRequest for each entity to the request collection.
foreach (var entity in input.Entities)
{
CreateRequest createRequest = new CreateRequest { Target = entity };
requestWithResults.Requests.Add(createRequest);
}
// Execute all the requests in the request collection using a single web method call.
ExecuteMultipleResponse responseWithResults =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithResults);
完整样本在这里这不起作用。并发执行的任务不能共享同一IOOrganizationService实例。您需要一个提供可重用服务实例的对象池。将池中的实例数限制为最多10个
我建议使用BlockingCollection的生产者-消费者模式来安排需要完成的工作。请参阅。我会将循环移动到自己的线程中,并根据可能的执行速度,使for循环为每次迭代创建自己的线程。这将释放主线程来完成其他工作,而其他线程则完成它们的工作。@Ortund您能用示例代码解释一下吗?我不清楚你想在这里说什么@rahuldesai我无法发布答案,事实上,我本应该投票结束这个问题,因为它被搁置的确切原因,但我会这么做。。。这只会提供有限的吞吐量增益。如果正确编码,这种方法可以实现每小时约100万次在线操作,如果这还不够,则CRM不是完成此任务的正确工具。。。