python bottle+sqlite3で複数ユーザの更新を受け付ける方法 の質問をした時に、下記のコメントをいただきました。

answer 関数や init_table 関数で with sqlite3.connect(db_name) as ... としていますけれども、ここは context manager を使って(from contextlib import closing)、with closing(sqlite3.connect(db_name)) as ... とすべきではないでしょうか

Python 3.xからSQLite3を呼び出した後にクローズ処理は必ず行うべきものでしょうか。
そしてクローズ処理を行う場合、どのコードが推奨されるでしょうか。

  1. contextlib.closing
    with closing(sqlite3.connect('hoge.db')) as c:
  2. try-finally
    finally: c.close()
  3. withのみ(クローズ無し?)
    with sqlite3.connect('hoge.db') as c:

無学ゆえにコメントをいただくまでcontextlib.closingの存在を知りませんでした。
日本語でsqlite3のサンプルコードを見ても、closingを使わずにwithのみが書かれているものや、finallyブロックを使わずに正常処理としてclose()を行うもの、close()しないものが多く見つかります。

本家SOの類似質問への回答では、下記について言及するとともにcontextlib.closingの使用を推奨しています。

However, the connection.__exit__() method doesn't close the connection, it commits the transaction on a successful completion, or aborts it when there is an exception.

意訳:
(flaskチュートリアルのconnect_db()connection managerのようにsqlite3のconnectionを返す。)だかしかしconnection.__exit__()関数は接続を切断しない。これはブロックの処理を正常に実行したらコミットし、例外が発生したら破棄する。

本家SOの別質問では、「クローズした方が良いんじゃない?」程度に軽く推奨しているように読み取れます。
クローズすることで利用者にはどのようなメリットがあるのでしょうか。

なお、withを使いclosingを使わない下記のスクリプトを並列処理しても、ロックはかからずに正常終了しました。
下記は複数ユーザが個別のプログラムで1つのデータベースファイルに同時アクセスする状況を再現する状況を、並列処理で強引に再現しようとしています。

import sqlite3
from contextlib import closing
from multiprocessing import Pool

#DBがなければ作る
def get_db():
    p = 'quiz.db'
    conn = sqlite3.connect(p)
    init_answer(conn)
    return conn

def init_answer(conn):
    if has_table(conn, 'answer'):
        return
    conn.execute(u"""
create table answer (
    auid varchar(50) primary key,
    avalue integer
);
"""
)

def has_table(conn, name):
    q = conn.execute("select count(*) from sqlite_master where type='table' and name='{0}'".format(name))
    c = q.fetchone()[0]
    return c != 0

def replace_row(i):
    # closingの有無にかかわらず、同時実行に正常終了する
    with sqlite3.connect('quiz.db') as conn:
    #with closing(sqlite3.connect('quiz.db')) as conn:
        conn.execute("replace into answer values(?, ?)", ('fuga', i))

if __name__ == '__main__':
    conn = get_db()
    conn.close()
    #同時アクセスのために効率の悪い並列処理を行っています。このコードを再利用する際にはベストアンサーもご参照願います。
    p = Pool(4)
    p.map(replace_row, list(range(100)))
    p.close()