Euler-Mascheroni Single Thread Speed Improvements
Firstly, this code has a couple of dozen PEP8 formatting violations. Following conventions generally helps readability.

Also on the subject of readability, comments providing references for the formulae used should be considered essential in mathematical software.




def agm(a, b):      #Arithmetic Geometric Mean



The conventional way of documenting a function is with a docstring. That also allows you to document the expected input types (decimal.Decimal? float?).




def pi_agm():       #Pi via AGM and lemniscate
    print('Computing Pi...')
    a, b, t, p, pi, k = 1, D(2).sqrt()/2, 1/D(2), 2, 0, 0
    while 1:
        an    = (a+b)/2
        b     = (a*b).sqrt()
        t    -= p*(a-an)**2
        a, p  = an, 2**(k+2)
        piold = pi
        pi    = ((a+b)**2)/(2*t)
        k    += 1
        if pi == piold:
            break
    return pi



The while loop is unnecessarily ugly: while True would be preferable. I would say that it would be even better to use the loop index as a loop index with for k in itertools.count(), but actually that variable is wholly unnecessary.

If find it unhelpful to initialise six variables in one line where some of them are quite complicated. On the other hand, it could be more helpful to combine some of the updates in the loop body. Perhaps the happy medium is something like

    a, b, t = 1, D(0.5).sqrt(), 1
    p, pi = 1, 0
    while True:
        a, b, t = (a+b)/2, (a*b).sqrt(), t - p*(a-b)**2
        p, piold, pi = 2*p, pi, (a+b)**2 / t


I'm not entirely convinced by


        if pi == piold:
            break



Sometimes iterative approaches in finite data types oscillate around the solution rather than converging definitively. It might be more robust to track the last two or three values and, on finding a loop, return the average of the values in the loop.




def factorial(x ,pfact, pfactprd):       
    x = int(x)



Do you expect to pass a non-int? See previous note about using docstrings to document types.


    if pfact == (x-1):
        return pfactprd*x
    else:
        factorial = D(1)
        for i in range(1, x+1):
            factorial *= i
        return factorial



Is the else ever actually used? Might it be more maintainable to remove this function entirely?




    def lntwosum(n, d, b):
        logsum, logold, e = D(0), D(0), 0
        while 1:
            logold = logsum
            logsum += D(1/((D(b**e))*((2*e)+1)))
            e += 1
            if logsum == logold:
                return (D(n)/D(d))*logsum



Here the previous comment about itertools.count is relevant.

I'm confused as to why D is invoked where it is. Without any comments to justify it, it appears to be done at random.




def lnagm(x):   #Natural log of via AGM,
    try:
        if int(x) == 1:
            return 0
        if int(x) == 2:
            return lntwo()
    except:
        pass



??? Are you expecting int(x) to throw an exception?




    pi = D(pi_agm())



See previous comments about appearing to use D at random. Here, if pi_agm() returns a decimal.Decimal then it's unnecessary, and if it doesn't then surely that would be a bug because pi won't have the necessary precision? I don't see any further polishing of its error.




    decimal.getcontext().prec = m
    ...
    logr = D(str(result)[:m//2])
    decimal.getcontext().prec = prec
    return logr



Would the following work?

    decimal.getcontext().prec = m
    ...
    decimal.getcontext().prec = prec
    return D(result)





    k = D(prec//2)
    ...
    upper = int((12*k)+2)



Why not just upper = 6*prec + 2 with no need to coerce?



Other earlier comments also apply to gamma.




#Calling Gamma
prec = int(input('Precision for Gamma: '))*8
decimal.getcontext().prec = prec
gam = gamma()
print('\n')
print(gam)



It's a Python best practice, which serves to make the file reusable as a library, to guard this with if __name__ == "__main__":.

A comment explaining the *8 would be useful. At a guess, prec is in bits?