Re: Async Design Question

Tech-Archive recommends: Speed Up your PC by fixing your registry



Shawn,

The reason this works for you is that you are passing the IAsyncResult
implementation, which happens to have a reference back to the delegate that
created it. Personally, I don't think that this is a good idea, since it
wastes the slot for information, should you need to pass that around (and I
wouldn't recommend this as standard practice).

However, as you show in your code, you can always cast the IAsyncResult
implementation to the AsyncResult instance which has a reference to the
delegate that created it. It is better to use this, and free up the slot
that has the data in it.

Also, your call to WaitOne on the AsyncWaitHandle property on the async
result is not needed. When you call EndInvoke, if the call hasn't
completed, it will block until it is.


--
- Nicholas Paldino [.NET/C# MVP]
- mvp@xxxxxxxxxxxxxxxxxxxxxxxxxxx

"Shawn B." <leabre@xxxxxxxx> wrote in message
news:uM7BHn4PFHA.2384@xxxxxxxxxxxxxxxxxxxxxxx
> Okay, I correct myself, I am creating a different delegate instance each
> time the command is created, so it isn't reusing the same instance.
>
>
> #region ExecuteTable Asynchronous
>
> public virtual IAsyncResult BeginExecuteTable(
> string sqlQuery,
> bool storedProcedure
> )
> {
> ExecuteTableDelegate result = new
> ExecuteTableDelegate(this.ExecuteTableAsync);
> return result.BeginInvoke(sqlQuery, storedProcedure, null, null);
> }
>
> public virtual IAsyncResult BeginExecuteTable(
> string sqlQuery,
> bool storedProcedure,
> AsyncCallback callback
> )
> {
> ExecuteTableDelegate result = new
> ExecuteTableDelegate(this.ExecuteTableAsync);
> return result.BeginInvoke(sqlQuery, storedProcedure, callback, result);
> }
>
>
> public virtual DataTable EndExecuteTable(IAsyncResult ar)
> {
> ExecuteTableDelegate result = null;
>
> if (ar.AsyncState != null)
> {
> result = (ExecuteTableDelegate)ar.AsyncState;
> }
> else
> {
> result = (ExecuteTableDelegate)((AsyncResult)ar).AsyncDelegate;
> }
>
> ar.AsyncWaitHandle.WaitOne();
> return result.EndInvoke(ar);
> }
>
> protected virtual DataTable ExecuteTableAsync(
> string sqlQuery,
> bool storedProcedure
> )
> {
> DbAsyncBase data = (DbAsyncBase)GetNewDalInstance();
> DataTable result = null;
>
> try
> {
> AsyncCounter++;
>
> foreach(IDbDataParameter param in Parameters)
> {
> data.Parameters.Add(param);
> }
>
> result = data.ExecuteTable(sqlQuery, storedProcedure);
> }
> finally
> {
> if (data != null)
> {
> data.Dispose();
> }
>
> AsyncCounter--;
> }
>
> return result;
> }
>
>
> #endregion
>
>
>
>
> "Shawn B." <leabre@xxxxxxxx> wrote in message
> news:%23%23EuEg4PFHA.2736@xxxxxxxxxxxxxxxxxxxxxxx
>> (I'm not the Original Poster)
>>
>> :: The reason for this is that the delegate instance is linked
>> :: to the IAsyncResult returned from the call to BeginInvoke,
>> :: and if you create a new one, it will not work. This is the
>> :: reason #5 can not be implemented. You can get around
>> :: this by creating another instance of your class, and having
>> :: that perform the async operation.
>>
>> This is a curious remark. I don't recall reading this in the MSDN
>> documentation.
>>
>> I created a data access component about 2 1/2 years ago (long before
> ADO.NET
>> 2.0 was ever announced and even before the data access application block
>> ever existed) that has ability to execute readers, scalars, datasets,
>> datatables, and nonqueries asyncronously (I am more than happy to provide
>> the source code if anyone wants it, C#, and very neat and tidy). This
> same
>> component has been in 3 production environments over the years and in
>> each
>> invenvironment there are close to about 3 million page requests per day.
> It
>> uses delegates internally to execute the async results, in much the same
> way
>> you described below. The only difference between what you describe and
> the
>> behaviors we receive, are that I can indeed execute as many commands as I
>> want simultaneously to return a datatable and all the results come back
> with
>> their proper results and the requests don't get queued. For example, if
>> I
>> execute 10 commands at the same time async (on the same object instance,
>> delegate instance) and each command requires 3 seconds to complete, then
>> I
>> only need to wait roughly 3 seconds before I have the results for all 10
>> commands properly.
>>
>> I'm curious what you mean by your above statement?
>>
>> Here's my source to demonstrate what I'm saying:
>>
>> private void button1_Click(object sender, System.EventArgs e)
>> {
>> SqlDataHelper data = null;
>> DataTable x = null;
>> DataTable y = null;
>> DataTable z = null;
>> DataTable t = null;
>>
>> try
>> {
>> data = new SqlDataHelper(connectionString);
>>
>> IAsyncResult ar1 = data.BeginExecuteTable("SELECT * FROM Orders",
>> false);
>> IAsyncResult ar2 = data.BeginExecuteTable("SELECT TOP 5000 * FROM
>> Invoices", false);
>> IAsyncResult ar3 = data.BeginExecuteTable("SELECT TOP 10000 * FROM
>> AuditLog", false);
>>
>> // Do something while the other 3 are still fetching
>> //
>> t = data.ExecuteTable("SELECT * FROM SalesGroups", false);
>>
>> foreach (DataRow row in t.Rows)
>> {
>> row[0] = 0;
>> }
>>
>> data.BeginExecuteReader("SELECT TOP 5 * FROM InventoryPieces", false,
>> new AsyncCallback(CallbackMethod));
>>
>> // Now we synchronize
>> //
>> x = data.EndExecuteTable(ar1);
>> y = data.EndExecuteTable(ar2);
>> z = data.EndExecuteTable(ar3);
>>
>> MessageBox.Show(t.Rows.Count.ToString());
>> MessageBox.Show(x.Rows.Count.ToString());
>> MessageBox.Show(y.Rows.Count.ToString());
>> MessageBox.Show(z.Rows.Count.ToString());
>> }
>> finally
>> {
>> if (data != null)
>> {
>> data.Dispose();
>> }
>> }
>> }
>>
>> public void CallbackMethod(IAsyncResult ar)
>> {
>> SqlDataHelper data = null;
>> IDataReader result = null;
>> int count = 0;
>>
>> try
>> {
>> data = new SqlDataHelper(connectionString);
>>
>> result = data.EndExecuteReader(ar);
>>
>> while (result.Read()) count++;
>> result.Close();
>>
>> MessageBox.Show("Callback: " + count.ToString());
>> }
>> catch (Exception ex)
>> {
>> throw;
>> }
>> finally
>> {
>> if (data != null)
>> {
>> data.Dispose();
>> }
>> }
>> }
>>
>>
>> If you would like to see my data access component I'll provide you a link
> to
>> download the source code.
>>
>>
>> Thanks,
>> Shawn
>>
>>
>>
>>
>> "Nicholas Paldino [.NET/C# MVP]" <mvp@xxxxxxxxxxxxxxxxxxxxxxxxxxx> wrote
> in
>> message news:O$uLJi3PFHA.1932@xxxxxxxxxxxxxxxxxxxxxxx
>> > Shawn,
>> >
>> > I believe that all but the last request will be able to be handled
>> with
>> > delegates.
>> >
>> > Basically, create a private delegate that has the same signature as
>> your
>> > synchronous method. When compiled, the delegate will create
>> > BeginInvoke
>> and
>> > EndInvoke methods which can be used to make the call asynchronously.
>> Then,
>> > all you have to do is expose the methods (BeginXXX and EndXXX) with the
>> same
>> > signatures as the corresponding methods on the delegate.
>> >
>> > When those methods are called, you just channel the call to a
> delegate
>> > instance and return the appropriate IAsyncResult. The delegate, of
>> course,
>> > points to your synchronous method implementation.
>> >
>> > The thing is, you have to store the delegate in your class
>> > instance,
>> and
>> > can only have one async operation at a time being performed. The
>> > reason
>> for
>> > this is that the delegate instance is linked to the IAsyncResult
> returned
>> > from the call to BeginInvoke, and if you create a new one, it will not
>> work.
>> > This is the reason #5 can not be implemented. You can get around this
> by
>> > creating another instance of your class, and having that perform the
> async
>> > operation.
>> >
>> > For 3 and 4, that is up to you to create the progress events and
>> > the
>> > cancel method. Basically, you would have a flag somewhere which
> indicates
>> > whether or not the operation should be cancelled. As your synchronous
>> > method is run, it checks the flag (access to the flag should be
>> synchronized
>> > through the lock statement) and if the flag is set, cancel the
> operation,
>> > and exit the method.
>> >
>> > Of course, if the method has a main loop that runs, it becomes very
>> > obvious where to check the flag to see if it is a cancelled operation.
>> >
>> > Hope this helps.
>> >
>> > --
>> > - Nicholas Paldino [.NET/C# MVP]
>> > - mvp@xxxxxxxxxxxxxxxxxxxxxxxxxxx
>> >
>> > "Shawn Meyer" <me@xxxxxx> wrote in message
>> > news:OkslPd3PFHA.2132@xxxxxxxxxxxxxxxxxxxxxxx
>> > > Hello -
>> > >
>> > > I am trying to write a class that has an async BeginX and EndX, plus
> the
>> > > regular X syncronous method. Delegates seemed like the way to go,
>> > > however, I still am having problems getting exactly what I want.
>> > > Here
>> are
>> > > my goals
>> > >
>> > > 1. I would like the IAsyncResult that is returned by the Begin
> function
>> to
>> > > be able to be waited on or polled to check for completion.
>> > > 2. The Begin function would take a callback, and the async process
> would
>> > > call it when the task is complete.
>> > > 3. I would like to have events such as ProgressChanged that get fired
> as
>> > > the
>> > > async process progresses.
>> > > 4. The async process should be able to be cancled with a function
>> CancelX.
>> > > 5. Multiple async tasks should be able to be performed at the same
> time.
>> > >
>> > > Are delegates the way to go? Can anyone provide me with a quick
> example
>> > > on
>> > > how to implement this.
>> > >
>> > > Thanks,
>> > > Shawn
>> > >
>> > >
>> >
>> >
>>
>>
>
>


.


Quantcast