2013-10-04 3 views
2

Мы пытаемся проверить замки. В принципе, существует несколько клиентов, пытающихся получить блокировку определенного ключа. В приведенном ниже примере мы использовали ключ «x».Как проверить параллелизм и блокировку в golang?

Я не знаю, как проверить, работает ли замок. Я могу только читать журналы, чтобы определить, работает ли он.

Правильная последовательность событий должна быть:

  1. client1 получает замок на ключ «х»
  2. client2 пытается получить блокировку на клавишу «х» (fmt.Println («2 получает замок»)) - но блокируется и ждет
  3. client1 релизы замок на ключ «х»
  4. client2 получает замок на ключ «х»

Q1: Как я могу автоматизировать процесс и превратить это в тест?

Q2: Каковы некоторые из советов по тестированию параллелизма/блокировки мьютексов вообще?

func TestLockUnlock(t *testing.T) { 
    client1, err := NewClient() 
    if err != nil { 
     t.Error("Unexpected new client error: ", err) 
    } 

    fmt.Println("1 getting lock") 
    id1, err := client1.Lock("x", 10*time.Second) 
    if err != nil { 
     t.Error("Unexpected lock error: ", err) 
    } 
    fmt.Println("1 got lock") 

    go func() { 
     client2, err := NewClient() 
     if err != nil { 
      t.Error("Unexpected new client error: ", err) 
     } 
     fmt.Println("2 getting lock") 
     id2, err := client2.Lock("x", 10*time.Second) 
     if err != nil { 
      t.Error("Unexpected lock error: ", err) 
     } 
     fmt.Println("2 got lock") 

     fmt.Println("2 releasing lock") 
     err = client2.Unlock("x", id2) 
     if err != nil { 
      t.Error("Unexpected Unlock error: ", err) 
     } 
     fmt.Println("2 released lock") 
     err = client2.Close() 
     if err != nil { 
      t.Error("Unexpected connection close error: ", err) 
     } 
    }() 

    fmt.Println("sleeping") 
    time.Sleep(2 * time.Second) 
    fmt.Println("finished sleeping") 

    fmt.Println("1 releasing lock") 
    err = client1.Unlock("x", id1) 
    if err != nil { 
     t.Error("Unexpected Unlock error: ", err) 
    } 

    fmt.Println("1 released lock") 

    err = client1.Close() 
    if err != nil { 
     t.Error("Unexpected connection close error: ", err) 
    } 

    time.Sleep(5 * time.Second) 
} 

func NewClient() *Client { 
    .... 
} 

func (c *Client) Lock(lockKey string, timeout time.Duration) (lockId int64, err error){ 
    .... 
} 

func (c *Client) Unlock(lockKey string) err error { 
    .... 
} 
+1

Если вы хотите протестировать параллелизм, вам нужно будет сделать несколько ходовых процедур и запустить их, ну, одновременно. Вы можете попытаться снять блокировку и преднамеренно заставить ее рушиться или ошибаться, одновременно изменяя вещи, а затем добавляя блокировку для обеспечения ее разрешения. Вы должны быть в состоянии сделать все это в рамках теста, который у вас выше. –

ответ

6

Параллельное тестирование кода, основанного на блокировке, является сложным, насколько трудно найти приемлемые решения. Специальное ручное тестирование по заявлениям печати не является идеальным.

Существует четыре проблемы динамического параллелизма, которые по существу не подлежат тестированию (more). Наряду с проверкой производительности статистический подход - это лучшее, что вы можете достичь с помощью тестового кода (например, установив, что производительность 90 процентов больше 10 мс или вероятность тупика менее 1%).

Это одна из причин, по которой подход Communicating Sequential Process (CSP), предоставляемый Go, лучше использовать, чем блокировки в общей памяти. Учтите, что ваш тест Goroutine предоставляет единицу с определенным поведением. Это можно протестировать против других Goroutines, которые обеспечивают необходимые тестовые входы через каналы и выводят результаты контроля по каналам.

С помощью CSP, используя Gorutines без какой-либо общей памяти (и без какой-либо непреднамеренно разделяемой памяти через указатели), гарантируется, что условия гонки не возникают при доступе к данным. Используя некоторые проверенные шаблоны проектирования (например, Welch, Justo and WIllcock), можно установить, что между Goroutines не будет взаимоблокировки. Затем остается установить, что функциональное поведение является правильным, для которого упомянутая выше тестовая упряжка Goroutine будет хорошо.

Смежные вопросы