How do you generate random unique identifiers in a multi-process and multi-threaded environment?

Every solution I came up with does not support a thread.

def uuid(cls,db):
    u = hexlify(os.urandom(8)).decode('ascii')
    db.execute('SELECT sid FROM sessions WHERE sid=?',(u,))
    if db.fetch(): u=cls.uuid(db)
    else: db.execute('INSERT INTO sessions (sid) VALUES (?)',(u,))
    return u
+3
source share
9 answers

Your algorithm is fine (thread safe as far as your API DB module is safe), and this is probably the best way. It will never give you duplicates (if you have a PRIMARY or UNIQUE key on sid), but you have a negligible chance of getting an exception IntegrityErrorin INSERT. But your code does not look very good. It is better to use a loop with a limited number of attempts instead of recursion (which in the case of some error in the code can become infinite):

for i in range(MAX_ATTEMPTS):
    sid = os.urandom(8).decode('hex')
    db.execute('SELECT COUNT(*) FROM sessions WHERE sid=?', (sid,))
    if not db.fetchone()[0]:
        # You can catch IntegrityError here and continue, but there are reasons
        # to avoid this.
        db.execute('INSERT INTO sessions (sid) VALUES (?)', (sid,))
        break
else:
    raise RuntimeError('Failed to generate unique session ID')

, . base64.urlsafe_b64encode() , SID , , (MySQL VARCHAR , , VARBINARY ).

+3
import os, threading, Queue

def idmaker(aqueue):
  while True:
    u = hexlify(os.urandom(8)).decode('ascii')
    aqueue.put(u)

idqueue = Queue.Queue(2)

t = threading.Thread(target=idmaker, args=(idqueue,))
t.daemon = True
t.start()

def idgetter():
  return idqueue.get()

Python - , " ". , "" , "" get / , (Queue ).

idqueue 2 ( , , , - , 2 , ;-), id , - . idgetter ( , idgetter = idqueue.get), , ( !) - , , , id .

+5

:

for i in range(MAX_ATTEMPTS):
    sid = os.urandom(8).decode('hex')
    try:
        db.execute('INSERT INTO sessions (sid) VALUES (?)', (sid,))
    except IntegrityError:
        continue
    break
else:
    raise RuntimeError('Failed to generate unique session ID')

. , .

( ).

+3

, , :

import threading
lock = threading.Lock()
def get_random_number(lock)
    with lock:
        print "This can only be done by one thread at a time"

, get_random_number, , .

, . , , .

+2

, :

>>> import uuid

# make a UUID based on the host ID and current time
>>> uuid.uuid1()
UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')

.

+1

(- ) -, .

+1

uid , :

BEGIN TRANSACTION
SELECT COUNT(*) FROM sessions WHERE sid=%s
INSERT INTO sessions (sid,...) VALUES (%s,...)
COMMIT
0

? . .

, , - . - . , , , , . , .

, ( - ) . , , .

, GUID. -, , .

, . . md5, , - md5, . sha1.

0

mkdtemp , :

def uuid():
    import tempfile,os
    _tdir = tempfile.mkdtemp(prefix='uuid_')
    _uuid = os.path.basename(_tdir)
    os.rmdir(_tdir)
    return _uuid
0

Source: https://habr.com/ru/post/1722098/


All Articles