Возврат информации о процессе из SQL Server - PullRequest
1 голос
/ 10 октября 2011

Все, у меня есть некоторый сложный код C # (Windows Forms), который тесно связан с обращениями к SQL Server (предполагаемая версия сервера - 2008 R2 или выше). Как это стоит. код является последовательным, и меня попросили многопоточность. Этот процесс многопоточности теперь конкретно связан с дорогими частями кода, то есть когда код выполняет «тяжелую работу». Большая часть работы выполняется с запросами SQL Server.

Я собираюсь приступить к многопоточности основного процессора, который обрабатывает вызовы к SQL Server. Я хочу предоставить информацию пользователю в порядке прогресса из «Нити SQL», поскольку процедуры SQL могут быть очень длинными. Я хочу знать, если мой метод звучит разумно или есть лучший способ сделать это. Мой подход заключается в следующем: (Примечание: приведенный ниже код является лишь небольшим примером, который я создал, прежде чем пытаться сделать это с реальным кодом)

A. Запустите поток BackgroundWorker из события нажатия кнопки на главной форме.

Bgw = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
Bgw.DoWork += new DoWorkEventHandler(Bgw_DoWork);
Bgw.ProgressChanged += new ProgressChangedEventHandler(Bgw_ProgressChanged);
Bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Bgw_RunWorkerCompleted);
Bgw.RunWorkerAsync();  

B. Из события Bgw_DoWork я запускаю свой метод SQL, который находится в классе HeavyWork.

void Bgw_DoWorkSQL(object sender, DoWorkEventArgs e)
{
    Hw = new HeavyWork(this, ref Bgw, ref e);
    Hw.SQLProc();
    return;
} 

C. Запустите другой фоновый поток из BackgroundWorker (на этот раз , а не BackgroundWorker) из Hw.SQLProc, чтобы отслеживать ход выполнения запросов SQL и облегчать отмену запроса SQL Server.

// Globals.
private bool bConnOpen = false;
private SqlConnection conn = null;
private Form _MainForm; 
private BackgroundWorker _Bgw;
private DoWorkEventArgs _e;    

public void SQLProc()
{
    bool bConnOpen = false;
    const string strSqlConnMaster = "Data Source = localhost; Initial Catalog = RMH1006DHFinal; Integrated Security " + "= True; MultipleActiveResultSets = True; Connection Timeout = 0";

    const string strSQL = "DBCC CHECKDB"; // Expensive SQL Non-Query.

    try
    {
        // Create new SQL connection.
        conn = new SqlConnection(strSqlConnMaster);

        // Execute the SQL Non-Query.
        conn.Open();
        bConnOpen = true;

        // Start another thread to get user information and for cancellation purposes.
        Thread SQLThread = new Thread(myMethod); // This is not working.
        SQLThread.IsBackground = true;
        SQLThread.Start();           

        // Now run big query.
        _Bgw.ReportProgress(0, String.Format("Processing SQL Command '{0}'...", strSQL));
        ExecNonQuery(conn, strSQL);
        conn.Close();
        bConnOpen = false;

        return;
    }
    catch (Exception)
    {
        throw;
    }
    finally
    {
        if (bConnOpen)
            conn.Close();
    }
}

Итак, я хочу запустить дорогой SQL-запрос на отдельном BackgroundWorker. В методе, вызываемом в потоке BackgroundWorker (какой-то запрос, отправленный с использованием соединения SQL, назовите его SqlConnection conn), запустите другой Thread, который переходит в другой метод, используя отдельный SqlConnection connNew, который извлекает информацию о главном процессе на conn.

Я хотел бы знать, это правильный способ сделать это? Кроме того, если возможно запустить новые Thread s из BackGroundWorker, так как код выше не запускает метод myMethod в новом потоке?

Спасибо всем заранее.

Ответы [ 2 ]

1 голос
/ 10 октября 2011

Если я правильно понимаю, вы хотите указать прогресс, но не можете, потому что ExecNonQuery блокирует.

В качестве хорошей практики я бы не использовал для этого BackgroundWorker, если ваш вызов db может занять больше, чем, скажем, секунду, поскольку BW использует поток пула потоков. Вместо этого я бы использовал новый поток или, если вы используете .NET 4.0, задачу с TaskCreationOptions.LongRunning.

Возвращаясь к вашим отчетам о прогрессе: ваши вызовы БД блокируются, поэтому единственный прогресс, который вы можете показать, выполняется или завершен, так что я бы показал какой-то индикатор прогресса выделения. Я бы управлял этим из потока пользовательского интерфейса с помощью таймера - вы действительно не хотите раскручивать поток, просто чтобы сделать анимацию, и вы все равно хотите быть в потоке пользовательского интерфейса.

1 голос
/ 10 октября 2011

Если вы хотите выделить новую тему из фоновой темы, это нормально.Однако, как вы заявили, то, как вы его настроили, не будет работать в его текущем состоянии.

Thread SQLThread = new Thread(myMethod); // This is not working. 

... должно стать ...

Thread SQLThread = new Thread(new ThreadStart(myMethod));
...

...или просто ...

Thread SQLThread = new Thread(()=>myMethod());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...