programing

스레드에서 생성된 개체는 동일한 스레드에서만 사용할 수 있습니다.

padding 2023. 9. 25. 22:23
반응형

스레드에서 생성된 개체는 동일한 스레드에서만 사용할 수 있습니다.

문제를 찾을 수 없습니다.

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm(request.form)
    if request.method=='POST' and form.validate():
        name =  form.name.data 
        email = form.email.data
        username = form.username.data
        password = sha256_crypt.encrypt(str(form.password.data))

        c.execute("INSERT INTO users(name,email,username,password) 
        VALUES(?,?,?,?)", (name, email, username, password))

        conn.commit

        conn.close()

오류:

파일 "C:\Users\app.py ", 59번 행, 레지스터 c.사용자에게 삽입(이름, 이메일, 사용자 이름, 암호) 값(?, ??), (이름, 이메일, 사용자 이름, 암호) 프로그래밍 오류: 스레드에서 생성된 SQLite 개체는 동일한 스레드에서만 사용할 수 있습니다.개체가 스레드 ID 23508에서 생성되었으며 스레드 ID 22640입니다.

HTML 파일에서 이름, 이메일 사용자 이름, 비밀번호를 사용할 수 없다는 뜻입니까?어떻게 해결해야 합니까?

데이터베이스에 연결할 때 다음을 추가합니다.

conn = sqlite3.connect('your.db', check_same_thread=False)

커서 'c'가 동일한 스레드에서 생성되지 않았습니다. 플라스크 앱을 실행할 때 초기화되었을 수 있습니다.

다음과 같은 동일한 방법으로 SQLite 개체(연결부 및 커서)를 생성할 수 있습니다.

  @app.route('/')
  def dostuff():
    with sql.connect("database.db") as con:
      name = "bob"
      cur = con.cursor()
      cur.execute("INSERT INTO students (name) VALUES (?)",(name))
      con.commit()
      msg = "Done"
engine = create_engine(
'sqlite:///restaurantmenu.db',
connect_args={'check_same_thread': False}
)

나를 위해 일함

다음을 시도해 볼 수 있습니다.

engine=create_engine('sqlite:///data.db', echo=True, connect_args={"check_same_thread": False})

그것은 나에게 효과가 있었다.

저의 경우, 두 개의 파이썬 파일이 sqlite 엔진을 생성하여 다른 스레드에서 작동하는 것과 같은 문제가 있습니다.여기서 SQLLchemy 문서를 읽어보면 두 파일 모두 싱글톤 기법을 사용하는 것이 더 나을 것 같습니다.

# maintain the same connection per thread
from sqlalchemy.pool import SingletonThreadPool
engine = create_engine('sqlite:///mydb.db',
                poolclass=SingletonThreadPool)

모든 경우를 해결할 수는 없지만, 가끔 같은 오류가 발생하지만 쉽게 극복할 수 있어 브라우저 페이지가 새로워집니다.코드 디버그를 할 때만 사용하기 때문에 저는 괜찮습니다.보다 영구적인 솔루션을 위해서는 Postgre와 같은 다른 데이터베이스를 선택해야 합니다.SQL 또는 기타 데이터베이스

https://docs.python.org/3/library/sqlite3.html 에서 언급하고 @Snidhi Sofpro가 댓글로 지적한 바와 같이

기본적으로 check_same_thread는 True이고 생성 스레드만 연결을 사용할 수 있습니다.False를 설정하면 반환된 연결이 여러 스레드에서 공유될 수 있습니다.연결이 동일한 여러 스레드를 사용하는 경우 데이터 손상을 방지하기 위해 쓰기 작업을 사용자가 직렬화해야 합니다.

직렬화를 달성하는 한 가지 방법:

import threading
import sqlite3
import queue
import traceback
import time
import random

work_queue = queue.Queue()

def sqlite_worker():
    con = sqlite3.connect(':memory:', check_same_thread=False)
    cur = con.cursor()
    cur.execute('''
        CREATE TABLE IF NOT EXISTS test (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            text TEXT,
            source INTEGER,
            seq INTEGER
        )
    ''')
    while True:
        try:
            (sql, params), result_queue = work_queue.get()
            res = cur.execute(sql, params)
            con.commit()
            result_queue.put(res)
        except Exception as e:
            traceback.print_exc()

threading.Thread(target=sqlite_worker, daemon=True).start()

def execute_in_worker(sql, params):
    # you might not really need the results if you only use this
    # for writing unless you use something like https://www.sqlite.org/lang_returning.html
    result_queue = queue.Queue()
    work_queue.put(((sql, params), result_queue))
    return result_queue.get(timeout=5)

def insert_test_data(seq):
    time.sleep(random.randint(0, 100) / 100)
    execute_in_worker(
        'INSERT INTO test (text, source, seq) VALUES (?, ?, ?)',
        ['foo', threading.get_ident(), seq]
    )

threads = []
for i in range(10):
    thread = threading.Thread(target=insert_test_data, args=(i,))
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

for res in execute_in_worker('SELECT * FROM test', []):
    print(res)

# (1, 'foo', 139949462500928, 9)
# (2, 'foo', 139949496071744, 5)
# (3, 'foo', 139949479286336, 7)
# (4, 'foo', 139949487679040, 6)
# (5, 'foo', 139949854099008, 3)
# (6, 'foo', 139949470893632, 8)
# (7, 'foo', 139949862491712, 2)
# (8, 'foo', 139949845706304, 4)
# (9, 'foo', 139949879277120, 0)
# (10, 'foo', 139949870884416, 1)

되어 있지만 에 .while

저도 같은 문제가 있어서 매번 전화를 걸 때마다 연결을 닫아 고쳤습니다.

results = session.query(something, something).all()
session.close()

는 에 .execute()데, 즉 SQLite DB 입니다입니다.
나는 당신이 다음을 가지고 있다고 생각합니다.

conn = sqlite3.connect('your_database.db')
c = conn.cursor()

플라스크 스크립트의 맨 위 어딘가에 있습니다. 스크립트를 처음 실행할 때 초기화됩니다.
때.register함수가 호출되고, 초기 스크립트 실행과는 다른 새로운 스레드가 프로세스를 처리합니다.따라서 이 새로운 스레드에서는 SQLite가 오류로 캡처하는 다른 스레드의 개체 인스턴스를 사용하게 됩니다. 앱 실행 중에 다른 스레드에 의해 DB에 액세스할 것으로 예상되는 경우 데이터가 손상될 수 있기 때문입니다.
따라서 다른 방법으로, 동일 스레드 확인 SQLite 기능을 비활성화하는 대신 호출 중인 HTTP Method 내에서 DB 연결 및 커서 초기화를 시도할 수 있습니다.
이렇게 하면 실행 시 SQLite 개체 및 활용률이 동일한 스레드에 있게 됩니다.

코드는 중복되지만 데이터가 비동기적으로 액세스되는 상황에서 사용자를 보호하고 데이터 손상을 방지할 수 있습니다.

이것들이 사실입니까?

  • app인에@app.route플라스크 앱입니다.
  • 로컬 개발 서버를 실행하는 동안 이 오류가 발생합니다.
  • 합니다.app.run()

그렇다면 문제는 Flask 개발 서버가 기본적으로 멀티 스레드라는 것입니다.이 문제는 전화를 통해 해결할 수 있습니다.run와 함께threaded=False:

app.run(threaded=False)

저는 이 문제를 겪고 있었고 이 게시물에 답을 사용하고 있습니다.여기에 다시 게시할 내용:

creator = lambda: sqlite3.connect('file::memory:?cache=shared', uri=True)
engine = sqlalchemy.create_engine('sqlite://', creator=creator)
engine.connect()

따라서 이 문자열 "file::memory:? cache=shared"를 sqalchemy에 URL로 지정할 수 없다는 문제를 우회합니다.저는 많은 답변을 보았지만 이를 통해 여러 스레드 간에 공유되는 메모리 데이터베이스에서 SQLite를 사용할 때의 모든 문제가 해결되었습니다.속도를 위해 두 개의 스레드로 두 개의 테이블을 만들어 데이터베이스를 초기화합니다.이 전에는 파일이 백업된 DB를 사용하는 것이 유일한 방법이었습니다.그러나 이로 인해 클라우드 구현 시 지연 시간 문제가 발생했습니다.

"database.py " 만들기:

import sqlite3

def dbcon():
    return sqlite3.connect("your.db")

그런 다음 가져오기:

from database import dbcon

db = dbcon()

db.execute("INSERT INTO users(name,email,username,password) 
        VALUES(?,?,?,?)", (name, email, username, password))

실이 바로 끊어지기 때문에 닫지 않아도 될 것입니다.

언급URL : https://stackoverflow.com/questions/48218065/objects-created-in-a-thread-can-only-be-used-in-that-same-thread

반응형