Parallel.For is very slow when I am trying to call HTTPWebRequest function - parallel.for

In this method, I am trying to loop through DataSet.Table which has approx. 65K records only , however, the loop is taking for every or it fails with Aggregate exception.
Can somebody please point me what am I doing wrong?
Parallel.For(0, dataSet.Tables[0].Rows.Count, row =>
{
try
{
var downloadedValue = Helper.GetResponse(<<WebRequestMethod>>)");
if (downloadedValue != null)
{
actualTable.Rows.Add(dataSet.Tables[0].Rows[row]["Id"].ToString(), dataSet.Tables[0].Rows[row]["LastModifiedDate"].ToString());
}
}
catch(AggregateException e)
{
Console.WriteLine(e.ToString());
}
});

Related

IPageRetriever not working with Ajax calls

I have the following API call to retrieve page data
List<VillageNewsItem> newsList = pageRetriever.RetrieveAsync<VillageNewsItem>(
query => query
.Path("/Home/Village-News", PathTypeEnum.Children)
.Published(true)
.OnSite(SiteContext.CurrentSiteName)
.OrderByDescending(x => x.DocumentCreatedWhen)
)?.Result?.ToList();
It works fine and return 2 records if I run the query on page load. Inside Index action of the controller.
public VillageNewsListController(IPageDataContextRetriever dataRetriever, VillageNewsListRepository villageNewsListRepository,
IPageRetriever pagesRetriever, IPageDataContextRetriever pageDataContextRetriever, IPageUrlRetriever pageUrlRetriever)
{
this._dataRetriever = dataRetriever;
this._villageNewsListRepository = villageNewsListRepository;
this._pagesRetriever = pagesRetriever;
this.pageDataContextRetriever = pageDataContextRetriever;
this.pageUrlRetriever = pageUrlRetriever;
}
public async Task<ActionResult> Index(CancellationToken cancellationToken)
{
try
{
List<VillageNewsItem> newsList = pagesRetriever.RetrieveAsync<VillageNewsItem>(
query => query
.Path("/Home/Village-News", PathTypeEnum.Children)
.Published(true)
.OnSite(SiteContext.CurrentSiteName)
.OrderByDescending(x => x.DocumentCreatedWhen)
)?.Result?.ToList();
newsItems.VillageNewsItems = newsList;
return View(newsItems);
}
catch (Exception ex)
{
ErrorHandler.EventLog.LogError(ex.Source, ex.Message, ex.StackTrace);
return RedirectToAction("ErrorPage", "Error");
}
}
However, if I try to make the same API call via a client side AJAX call, it doesn't work and return 0 records. Why it's not working with Ajax calls?
Ajax call
function loadMoreNews() {
$.ajax({
url: '/VillageNewsList/VillageNewsItemList',
//data: { "term": request.term },
type: "POST",
success: function (data) {
response($.map(data,
function (item) {
console.log(data);
}));
},
error: function (response) {
//alert(response.responseText);
},
failure: function (response) {
// alert(response.responseText);
}
});
}
Server side method.
[HttpPost]
[Route("VillageNewsList/VillageNewsItemList")]
public VillageNewsListViewModel VillageNewsItemList(string NodeAliasPath = "", int villageId = 0, string state = "", int page = 1, int pageSize = 4)
{
try
{
List<VillageNewsItem> newsList = pagesRetriever.RetrieveAsync<VillageNewsItem>(
query => query
.Path("/Home/Village-News", PathTypeEnum.Children)
.Published(true)
.OnSite(SiteContext.CurrentSiteName)
.OrderByDescending(x => x.DocumentCreatedWhen)
)?.Result?.ToList();
var model = new VillageNewsListViewModel
{
VillageNewsItems = newsList, // returns 0 records
};
return model;
}
catch (Exception ex)
{
ErrorHandler.EventLog.LogError(ex.Source, ex.Message, ex.StackTrace);
//return RedirectToAction("ErrorPage", "Error");
}
return null;
}
Couple things I see.
You're calling IPageRetriever.RetrieveAsync, but you aren't putting an await before it. There may be some odd behavior due to this. Get rid of the ?.Result?.ToList() and instead just put await before it, it will return an IEnumerable of the specified type.
You don't need ".Published" nor "OnSite" with IPageRetriever, this API automatically uses the Current Site Context, the current culture, and either Published or not / Latest Version or not based on if it's in edit/preview mode or not.
See if those things fix the issue!
I also asume it is caused by async context here...
You can try to use a document query instead.
Would be something like this:
var items = new DocumentQuery<VillageNewsItem>(
.Path("/Home/Village-News", PathTypeEnum.Children)
.PublishedVersion()
.Published()
.OnCurrentSite()
.OrderByDescending(x => x.DocumentCreatedWhen))
?.Result
?.ToList();
If you have multiple cultures, add the culture to your query, too.
.Culture(LocalizationContext.CurrentCulture.CultureCode)

lotus.domino.local.Item cannot be cast to lotus.domino.RichTextItem

I try to put a file into a richtext but it crashes !
In my first code, I try to use directly "getFirstItem", in first time it was ok but now i try to use it again and it crashed.
In second time i pass with an object and it find my obj doesn't an richtextItem (instanceof) ???
I don't understand.
I have the message : "lotus.domino.local.Item cannot be cast to lotus.domino.RichTextItem" ?
Could you help me ?
public void copieFichierDansRichText(String idDocument, String nomRti, File file,
String nameFichier, String chemin) throws NotesException {
lotus.domino.Session session = Utils.getSession();
lotus.domino.Database db = session.getCurrentDatabase();
lotus.domino.Document monDoc = db.getDocumentByUNID(idDocument);
lotus.domino.RichTextItem rtiNew = null;
try {
try {
if (monDoc != null) {
// if (monDoc.getFirstItem(nomRti) != null) {
// rtiNew = (lotus.domino.RichTextItem)
// monDoc.getFirstItem(nomRti);
// } else {
// rtiNew = (lotus.domino.RichTextItem)
// monDoc.createRichTextItem(nomRti);
// }
Object obj = null;
if (monDoc.getFirstItem(nomRti) != null) {
obj = monDoc.getFirstItem(nomRti);
if (obj instanceof lotus.domino.RichTextItem) {
rtiNew = (lotus.domino.RichTextItem) obj;
}
} else {
obj = monDoc.createRichTextItem(nomRti);
if (obj instanceof lotus.domino.RichTextItem) {
rtiNew = (lotus.domino.RichTextItem) obj;
}
}
PieceJointe pieceJointe = new PieceJointe();
pieceJointe = buildPieceJointe(file, nameFichier, chemin);
rtiNew.embedObject(EmbeddedObject.EMBED_ATTACHMENT, "", pieceJointe.getChemin()
+ pieceJointe.getNomPiece(), pieceJointe.getNomPiece());
monDoc.computeWithForm(true, false);
monDoc.save(true);
}
} finally {
rtiNew.recycle();
monDoc.recycle();
db.recycle();
session.recycle();
}
} catch (Exception e) {
e.printStackTrace();
}
}
EDIT : I try to modify my code with yours advices but the items never considerate as richtextitem. It is my problem. I don't understand why, because in my field it is a richtext ! For it, the item can't do :
rtiNew = (lotus.domino.RichTextItem) item1;
because item1 not be a richtext !!!
I was trying to take all the fields and pass in the item one by one, and it never go to the obj instance of lotus.domini.RichTextItem....
Vector items = doc.getItems();
for (int i=0; i<items.size(); i++) {
// get next element from the Vector (returns java.lang.Object)
Object obj = items.elementAt(i);
// is the item a RichTextItem?
if (obj instanceof RichTextItem) {
// yes it is - cast it as such // it never go here !!
rt = (RichTextItem)obj;
} else {
// nope - cast it as an Item
item = (Item)obj;
}
}
A couple of things. First of all I would set up a util class method to handle the object recycling in a neater way:
public enum DominoUtil {
;
public static void recycle(Base... bases) {
for (Base base : bases) {
if (base != null) {
try {
base.recycle();
} catch (Exception e) {
// Do nothing
}
}
}
}
}
Secondly I would remove the reduntants try/catch blocks and simplify it like this:
private void copieFichierDansRichText(String idDocument, String nomRti, File file,
String nameFichier, String chemin) {
Session session = DominoUtils.getCurrentSession();
Database db = session.getCurrentDatabase();
Document monDoc = null;
try {
monDoc = db.getDocumentByUNID(idDocument);
Item item = monDoc.getFirstItem(nomRti);
if (item == null) {
item = monDoc.createRichTextItem(nomRti);
} else if (item.getType() != Item.RICHTEXT) {
// The item is not a rich text item
// What are you going to do now?
}
RichTextItem rtItem = (RichTextItem) item;
PieceJointe pieceJointe = new PieceJointe();
pieceJointe = buildPieceJointe(file, nameFichier, chemin);
rtItem.embedObject(EmbeddedObject.EMBED_ATTACHMENT, "", pieceJointe.getChemin()
+ pieceJointe.getNomPiece(), pieceJointe.getNomPiece());
monDoc.computeWithForm(true, false);
monDoc.save(true);
} catch (NotesException e) {
throw new FacesException(e);
} finally {
DominoUtil.recycle(monDoc);
}
}
Finally, apart from the monDoc, you need not recycle anything else. Actually Session would be automatically recycled and anything beneath with it (so no need to recycle db, let alone the session!, good rule is don't recycle what you didn't instantiate), but it's not bad to keep the habit of keeping an eye on what you instantiate. If it were a loop with many documents you definitively want to do that. If you also worked with many items you would want to recycle them as early as possible. Anyway, considered the scope of the code it's sufficient like this. Obviously you would call DominoUtil.recycle directly from the try block. If you have multiple objects you can recycle them at once possibly by listing them in the reverse order you set them (eg. DominoUtil.recycle(item, doc, view)).
Also, what I think you miss is the check on the item in case it's not a RichTextItem - and therefore can't be cast. I put a comment where I think you should decide what to do before proceeding. If you let it like that and let the code proceed you will have the code throw an error. Always better to catch the lower level exception and re-throw a higher one (you don't want the end user to know more than it is necessary to know). In this case I went for the simplest thing: wrapped NotesException in a FacesException.

C# how to call async await in a for loop

I am developing a quartz.net job which runs every 1 hour. It executes the following method. I am calling a webapi inside a for loop. I want to make sure i return from the GetChangedScripts() method only after all thread is complete? How to do this or have i done it right?
Job
public void Execute(IJobExecutionContext context)
{
try
{
var scripts = _scriptService.GetScripts().GetAwaiter().GetResult();
}
catch (Exception ex)
{
_logProvider.Error("Error while executing Script Changed Notification job : " + ex);
}
}
Service method:
public async Task<IEnumerable<ChangedScriptsByChannel>> GetScripts()
{
var result = new List<ChangedScriptsByChannel>();
var currentTime = _systemClock.CurrentTime;
var channelsToProcess = _lastRunReader.GetChannelsToProcess().ToList();
if (!channelsToProcess.Any()) return result;
foreach (var channel in channelsToProcess)
{
var changedScripts = await _scriptRepository.GetChangedScriptAsync(queryString);
if (changedScriptsList.Any())
{
result.Add(new ChangedScriptsByChannel()
{
ChannelCode = channel.ChannelCode,
ChangedScripts = changedScriptsList
});
}
}
return result;
}
As of 8 days ago there was a formal announcement from the Quartz.NET team stating that the latest version, 3.0 Alpha 1 has full support for async and await. I would suggest upgrading to that if at all possible. This would help your approach in that you'd not have to do the .GetAwaiter().GetResult() -- which is typically a code smell.
How can I use await in a for loop?
Did you mean a foreach loop, if so you're already doing that. If not the change isn't anything earth-shattering.
for (int i = 0; i < channelsToProcess.Count; ++ i)
{
var changedScripts =
await _scriptRepository.GetChangedScriptAsync(queryString);
if (changedScriptsList.Any())
{
var channel = channelsToProcess[i];
result.Add(new ChangedScriptsByChannel()
{
ChannelCode = channel.ChannelCode,
ChangedScripts = changedScriptsList
});
}
}
Doing these in either a for or foreach loop though is doing so in a serialized fashion. Another approach would be to use Linq and .Select to map out the desired tasks -- and then utilize Task.WhenAll.

Let the tasks race

Suppose I have a BlockingCollection OutputQueue, which has many items. Current my code is:
public void Consumer()
{
foreach (var workItem in OutputQueue.GetConsumingEnumerable())
{
PlayMessage(workItem);
Console.WriteLine("Works on {0}", workItem.TaskID);
OutLog.Write("Works on {0}", workItem.TaskID);
Thread.Sleep(500);
}
}
Now I want PlayMessage(workItem) running in the multiple tasks way because some workItem need more time, the others need less time. There are huge difference.
As for the method PlayMessage(workItem), it has a few service calls, play text to speech and some logging.
bool successRouting = serviceCollection.SvcCall_GetRoutingData(string[] params, out ex);
bool successDialingService = serviceCollection.SvcCall_GetDialingServiceData(string[] params, out excep);
PlayTTS(workItem.TaskType); // playing text to speech
So how to change my code?
What I thought was:
public async Task Consumer()
{
foreach (var workItem in OutputQueue.GetConsumingEnumerable())
{
await PlayMessage(workItem);
Console.WriteLine("Works on {0}", workItem.TaskID);
OutLog.Write("Works on {0}", workItem.TaskID);
Thread.Sleep(500);
}
}
Since you want parallelism with your PlayMessage, i would suggest looking into TPL Dataflow, as it combines both parallel work with async, so you could await your work properly.
TPL Dataflow is constructed of Blocks, and each block has its own characteristics.
Some popular ones are:
ActionBlock<TInput>
TransformBlock<T, TResult>
I would construct something like the following:
var workItemBlock = new ActionBlock<WorkItem>(
workItem =>
{
PlayMessage(workItem);
Console.WriteLine("Works on {0}", workItem.TaskID);
OutLog.Write("Works on {0}", workItem.TaskID);
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = // Set max parallelism as you wish..
});
foreach (var workItem in OutputQueue.GetConsumingEnumerable())
{
workItemBlock.Post(workItem);
}
workItemBlock.Complete();
Here's another solution, not based on TPL Dataflow. It uses uses SemaphoreSlim to throttle the number of parallel playbacks (warning, untested):
public async Task Consumer()
{
var semaphore = new SemaphoreSlim(NUMBER_OF_PORTS);
var pendingTasks = new HashSet<Task>();
var syncLock = new Object();
Action<Task> queueTaskAsync = async(task) =>
{
// be careful with exceptions inside "async void" methods
// keep failed/cancelled tasks in the list
// they will be observed outside
lock (syncLock)
pendingTasks.Add(task);
await semaphore.WaitAsync().ConfigureAwait(false);
try
{
await task;
}
catch
{
if (!task.IsCancelled && !task.IsFaulted)
throw;
// the error will be observed later,
// keep the task in the list
return;
}
finally
{
semaphore.Release();
}
// remove successfully completed task from the list
lock (syncLock)
pendingTasks.Remove(task);
};
foreach (var workItem in OutputQueue.GetConsumingEnumerable())
{
var item = workItem;
Func<Task> workAsync = async () =>
{
await PlayMessage(item);
Console.WriteLine("Works on {0}", item.TaskID);
OutLog.Write("Works on {0}", item.TaskID);
Thread.Sleep(500);
});
var task = workAsync();
queueTaskAsync(task);
}
await Task.WhenAll(pendingTasks.ToArray());
}

How to create and call the method(Using Thread C#) in for each loop?

I wanted to call my custom method in the Thread.
public void LoopOverAllLists(String _webAndSiteXml)
{
try
{
XmlNode _nodelist = SharePoint.ListsGetListCollection();
foreach (System.Xml.XmlNode _item in _nodelist.ChildNodes)
{
string title = _item.Attributes["Title"].Value;
//check for hidden list
if (_item.Attributes["Hidden"].Value.ToLower() == "false")
{
switch (_item.Attributes["ServerTemplate"].Value)
{
//Check whether list is document library
case SharePoint.LIST_ID_DOCUMENT_LIBRARY:
case SharePoint.LIST_ID_XML_FORMS:
case SharePoint.Publishing_ID_Pages:
{
//Get all documents info
try
{
GetAllDocumentsInfo(_item, _webAndSiteXml);
}
catch
{
}
break;
}
//Check whether list is having attachment
case SharePoint.LIST_ID_GENERIC:
case SharePoint.LIST_ID_ANNOUNCEMENTS:
case SharePoint.LIST_ID_CONTACTS:
case SharePoint.LIST_ID_TASKS:
case SharePoint.LIST_ID_EVENTS:
case SharePoint.LIST_ID_CUSTOM_GRID:
case SharePoint.LIST_ID_MEETING_SERIES:
case SharePoint.LIST_ID_MEETING_AGENDA:
case SharePoint.LIST_ID_MEETING_ATTENDEES:
case SharePoint.LIST_ID_MEETING_DECISIONS:
case SharePoint.LIST_ID_MEETING_OBJECTIVES:
case SharePoint.LIST_ID_MEETING_TTB:
case SharePoint.LIST_ID_MEETING_WS_PAGES:
case SharePoint.LIST_ID_PORTAL_SITE_LIST:
{
//Get all list items info having attachment
try
{
GetAllListItemsInfoOnlyAttachments(_item, _webAndSiteXml);
}
catch
{
}
break;
}
default:
GetAllListItemsInfoOnlyAttachments(_item, _webAndSiteXml);
break;
}
// Get All the List Forms
try
{
GetAllListForms(title, _webAndSiteXml);
}
catch
{
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
in above method three methods which is " GetAllDocumentsInfo , GetAllListItemsInfoOnlyAttachments and GetAllListForms " I wanted to call these function using thread in C#.
Thanks
Here is how I would approach the problem. Notice that I encapsulated the contents of the foreach loop into a separate method and then queued the execution of that method into the ThreadPool so that each iteration of the loop occurs in parallel. I also use a well established pattern to wait for all pending work items to complete. This code is compatible with .NET 3.5.
public void LoopOverAllLists(String _webAndSiteXml)
{
int pending = 1; // Used to track the number of pending work items.
var finished = new ManualResetEvent(false); // Used to wait for all work items to complete.
XmlNode nodes = SharePoint.ListsGetListCollection();
foreach (XmlNode item in nodes)
{
XmlNode capture = item; // This is required to capture the loop variable correctly.
Interlocked.Increment(ref pending); // There is another work item in progress.
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
ProcessNode(capture);
}
finally
{
// Signal the event if this is the last work item to complete.
if (Interlocked.Decrement(ref pending) == 0) finished.Set();
}
}, null);
}
// Signal the event if the for loop was last work item to complete.
if (Interlocked.Decrement(ref pending) == 0) finished.Set();
// Wait for all work items to complete.
finished.WaitOne();
}
private void ProcessNode(XmlNode item)
{
// Put the contents of your loop here.
}
instead of calling
GetAllDocumentsInfo(_item, _webAndSiteXml);
use
Task.Factory.StartNew(() => GetAllDocumentsInfo(_item, _webAndSiteXml));
repeat this pattern for the other method calls as well

Resources