Почему структура BitVector 32 более эффективна, чем BitArray?

Вы хотите убедиться, что Begin(), Commit() и Rollback() появляются в одной и той же функции. Это облегчает отслеживание транзакций и позволяет вам гарантировать их правильное закрытие с помощью defer.

Вот пример этого, который делает Commit или Rollback в зависимости от того, возвращена ли ошибка:

func (s Service) DoSomething() (err error) {
    tx, err := s.db.Begin()
    if err != nil {
        return
    }
    defer func() {
        if err != nil {
            tx.Rollback()
            return
        }
        err = tx.Commit()
    }()
    if _, err = tx.Exec(...); err != nil {
        return
    }
    if _, err = tx.Exec(...); err != nil {
        return
    }
    // ...
    return
}

Это может стать немного повторяющимся. Еще один способ сделать это - обернуть ваши транзакции с помощью обработчика транзакций:

func Transact(db *sql.DB, txFunc func(*sql.Tx) error) (err error) {
    tx, err := db.Begin()
    if err != nil {
        return
    }
    defer func() {
        if p := recover(); p != nil {
            tx.Rollback()
            panic(p) // re-throw panic after Rollback
        } else if err != nil {
            tx.Rollback() // err is non-nil; don't change it
        } else {
            err = tx.Commit() // err is nil; if Commit returns error update err
        }
    }()
    err = txFunc(tx)
    return err
}

Используя описанный выше инструмент транзакции, я могу сделать это:

func (s Service) DoSomething() error {
    return Transact(s.db, func (tx *sql.Tx) error {
        if _, err := tx.Exec(...); err != nil {
            return err
        }
        if _, err := tx.Exec(...); err != nil {
            return err
        }
        return nil
    })
}

. обеспечивает правильную обработку транзакций.

В моем обработчике транзакций я использую recover(), чтобы поймать панику, чтобы убедиться, что откат происходит немедленно. Я повторно выбрасываю панику, чтобы позволить моему коду перехватить ее, если ожидается паника. При нормальных обстоятельствах паника не должна возникать. Вместо этого должны быть возвращены ошибки.

Если бы мы не справились с паникой, транзакция в конце концов была бы отменена. Неподтвержденная транзакция откатывается базой данных, когда клиент отключается или когда транзакция получает сборщик мусора. Однако ожидание самостоятельного разрешения транзакции может вызвать другие (неопределенные) проблемы. Так что лучше решить это как можно быстрее.

Одна вещь, которая может быть не сразу понятна, это то, что defer может изменить возвращаемое значение в замыкании, если возвращаемая переменная захвачена. В обработчике транзакции транзакция фиксируется, когда err (возвращаемое значение) равно нулю. Вызов Commit также может вернуть ошибку, поэтому мы устанавливаем его возвращение на err с помощью err = tx.Commit(). Мы не делаем то же самое с Rollback, потому что err не ноль, и мы не хотим перезаписывать существующую ошибку.

15
задан rohancragg 29 October 2009 в 17:25
поделиться

2 ответа

BitVector32 is more efficient than BitArray for Boolean values and small integers that are used internally. A BitArray can grow indefinitely as needed, but it has the memory and performance overhead that a class instance requires. In contrast, a BitVector32 uses only 32 bits.

http://msdn.microsoft.com/en-us/library/system.collections.specialized.bitvector32.aspx

BitVector32 is a struct and consumes only 4 bytes. BitArray is a class that has overheads associated with it and is therefore less efficient - BitArray will need at least 8 bytes before you've even added any objects to it as it lives on the heap. More about the stack and heap here.

17
ответ дан 1 December 2019 в 02:20
поделиться

Вот что говорится в документации Microsoft для BitVector32 :

BitVector32 более эффективен, чем BitArray для логических значений и небольших целых чисел, которые используются внутри. BitArray может неограниченно увеличиваться по мере необходимости, но он требует дополнительных затрат памяти и производительности, которые требуются экземпляру класса. Напротив, BitVector32 использует только 32 бита.

Емкость BitVector32 ограничена 32 битами, размером int . Следовательно, индексирование и маскирование могут быть отдельными операциями. Сравните это с битовым массивом с 734 битами, и вы хотите узнать, установлен ли бит 197. Подумайте, как бы вы это сделали (с точки зрения разработчика класса).

8
ответ дан 1 December 2019 в 02:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: