0

I have this code in a method:

Task<int> linksCount = Task<int>.Factory.StartNew(() => { return DatabaseIn.GetUrlsCount(); });
Task<int> imagesCount = Task<int>.Factory.StartNew(() => { return DatabaseIn.GetImagesCount(); });

Later the linksCount and imagesCount.Result is displayed. However, when I run this code the first time. I get the following exception:

There is already an open DataReader associated with this Connection which must be closed first.

The code where the exception is thrown is:

MySqlCommand comm = null;
string cmdString = "SELECT COUNT(*) FROM damocles.imagestoassess;";

comm = new MySqlCommand(cmdString, conn);

if (comm.ExecuteScalar() == null)
{
    comm.Dispose();
    conn.Close();
    return 0;
}

int res = Convert.ToInt32(comm.ExecuteScalar());

comm.Dispose();
conn.Close();
return res;

The exception is thrown on the first call to ExecuteScalar. If I enclose the code in a try..catch clause the code continues but it throws another error in another part of the code.

Question:

  1. Why does it throw the exception? It doesn't throw any exception when run synchronously.
  2. How do I fix the code to work Asynchronously?

Thanks.

8
  • Is there any specific reason why you are using StartNew? Commented May 9, 2020 at 14:41
  • Does this answer your question? Exception: There is already an open DataReader associated with this Connection which must be closed first Commented May 9, 2020 at 14:42
  • 2
    It would appear you are using "async" and "parallel" interchangeably. You are launching two threads (in a wrong way too) that try to use the same connection object. In an async scenario, you would stay on the same thread, and the second query would start only after the first one completes (which would be perfectly async, but not in parallel). Connection objects do not like several async commands being in flight against them at the same time, this is not specific to mysql. If you absolutely want to run two queries in parallel, give each a separate connection object. Commented May 9, 2020 at 14:49
  • 1
    As a side note, you call comm.ExecuteScalar() twice, so you hit the database twice. You could optimize this by storing the result of the first call in a local variable. Commented May 9, 2020 at 14:49
  • 1
    Also please see stackoverflow.com/a/40065501/11683 for why async it's not going to work anyway even if you were to properly implement Task<int> GetUrlsCountAsync() and do int linksCount = await GetUrlsCountAsync(). Commented May 9, 2020 at 15:11

1 Answer 1

1

A MySqlConnection can only be used by one thread at a time. Your exception is happening because both Tasks are using the same conn object. For more details, see https://mysqlconnector.net/troubleshooting/connection-reuse/.

Your code will work if you create and use a new MySqlConnection inside each Task.

Additionally, it's a longstanding bug that async operations in MySql.Data aren't actually asynchronous. You'll need to switch to MySqlConnector to get asynchronous I/O for MySQL operations.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.